这星期在测试大并发的数据上报,测试过程中发现运行一段时间后,服务会卡住,不再响应请求,排查后发现 重启时,内存会不断增加,最终到达3G多卡死。
于是只能导出jvm运行的堆栈信息,分析内存泄露的问题。
首先是一些常用的命令。一类是jdk自带的分析工具,jmap用于分析jvm内存, jstack可以分析线程死锁,分析线程执行情况。还有阿里的 Arthas - Alibaba Java Diagnostic Tool 也是一个非常强大的工具,还能直接修改一些运行的内存类,分析方法执行返回,也是非常强大。
1. 查询java进程
首先 jps 命令可以查看运行中的java进程
2. jmap 可以分析内存
打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)。它的用途是为了展示java进程的内存映射信息,或者堆内存详情。
可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。
jmap -heap:format=b pid bin格式 javaversion 1.5
jmap -dump:format=b,file=filename pid javaversion >1.6
jmap -dump:format=b,file=outfile 3024可以将3024进程的内存heap输出出来到outfile文件里,再配合MAT(内存分析工具(Memory Analysis Tool)或与jhat (Java Heap Analysis Tool)一起使用,能够以图像的形式直观的展示当前内存是否有问题。
64位机上使用需要使用如下方式:
jmap -J-d64 -heap pid
导出日志快照:jmap -dump:format=b,file=heap.hprof pid
3. 分析快照:
分析快照有多种工具,比如jhat 、 virualvm 这都是jdk自带的工具。 jhat会分析快照文件,然后在后台起一个web服务,默认是使用7000端口,可以通过浏览器查看快照。
需要注意的是假如快照文件比较大,需要增大jhat的解析内存
用类似这样的命令: jhat -J-d64 -J-mx10g heap.hprof
jhat 分析jmap生成的dump文件 - hopeless-dream - 博客园
通过jdk自带的Java VisualVM对通过jmap导出的dump二进制文件转换堆栈转实例可视化文本内容进行分析 - 小木人印象
我没有使用上述工具分析,而是使用eclipse一个非常有用的插件: memory analyse,
Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation
需要注意两点,第一点是最新的版本最低要求java11, 我的jdk是java8,所以没有采用最新版本,而是安装的1.8版本, 第二点同样是内存不够的问题,可以修改配置文件,把JVM的堆内存调大
4. 分析
经过等待后,分析结果是线程池的队列溢出了,我发现不少人遇到过类似的问题,项目里面存在数据产生和数据消费,产生之后提交给线程池完成消费任务,数据消费的速率跟不上产生,于是在线程池的队列里面不断挤压,方法是提高线程池的处理线程数,提高消费的速率,然后就是给队列增加容量,防止无限增长,增加丢弃策略。
另外一个小tip:命令中增加OOM打印异常堆栈的命令是-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/jvmlogs/