并发编程:springboot并发内存溢出问题排查

1.问题概述

在生产环境中,大批量数据处理和并发数较多的情况下可能会出现stack溢出的情况,在排除常规的OOM因素之后,我们还需要在生产环境中进行场景复现以监控内存的使用情况,最后得出优化方案。

2.技术及工具

2.1相关概念

MAEMON:守护线程,当JVM中只有daemon线程时虚拟机关闭。典型的守护线程如:gc线程
PRIORITY:线程优先级

工具 说明
Jprofile 性能分析工具,收费
Jmap jdk内置,打印内存信息
Jstack jdk内置,打印堆栈信息
Mat eclipse插件,性能分析工具,安装版JDK11以上
Arthas 阿里开源新能分析工具

2.2命令实例

  • 查看当前运行的Java程序
    jps

  • 查看实例数目
    jmap -histo |grep ‘
    在这里插入图片描述

  • 查看线程状态及栈空间
    jstack -l |grep ‘
    在这里插入图片描述

  • 放开grep可以打印完整信息,最后一行显示当前线程正运行到哪一行
    并发编程:springboot并发内存溢出问题排查_第1张图片

  • 设置栈空间快照
    jstack >./stack.log

3.内存泄漏和溢出

org.apache.http.impl.client.HttpClientBuilder#evictIdleConnections(long, java.util.concurrent.TimeUnit)

RestTemplate发送请求调用底层的HttpClient,HttpClient会启动链接回收线程,当启用大批量的Http请求而没有配置链接池时就会发生这样的问题

4.生产实例

问题描述:在OCR定时任务中,存在并发发送大批量的HTTP请求到OCR服务器的情况,程序运行较长时间后会出现内存泄漏的情况,及:没有内存用以创建新的线程从而导致程序被迫暂停。

  • 查询堆空间实例情况
    jmap -histo > ./jmap.log
    并发编程:springboot并发内存溢出问题排查_第2张图片
    分析得知程序中有两处连接请求:
    1.OCR请求,每次请求都产生了守护线程org.apache.http.impl.client.IdleConnectionEvictor
    2.Minio请求,请求获取图片对象io.minio.MinioClient.Builder#httpClient,每次都生产okhttp线程
    3.Solr请求,org.apache.solr.client.solrj.impl.HttpSolrClient

  • 得到优化过后程序运行实例统计快照
    jps
    jmap -histo 3832 >./jmap02.log

  • 查看程序运行时堆空间快照
    jstack 3832 >./jstack.log

5.调试步骤总结

并发编程:springboot并发内存溢出问题排查_第3张图片

你可能感兴趣的:(企业级实战,开发小技巧,异常处理,java,后端)