一、使用Spring Boot Actuator生成HeapDump文件
参考我前面的文章Java|使用Spring Boot Actuator监控应用
访问http://localhost:1001/monitor/actuator/heapdump
即可生成heapdump文件。
二、安装分析工具MAT
在Java程序运行中发生OOM的时候,我们可以使用强大的内存分析工具MAT进行问题跟踪,但由于习惯了使用idea开发,所以安装MAT独立版。
下载地址:https://eclipse.org/mat/downloads.php
三、生成分析报告
首先,启动前面安装配置好的 Memory Analyzer tool(MAT) , 然后选择菜单项 File- Open Heap Dump 来加载需要分析的堆转储文件。
加载完之后的分析过程如下:
1.选择Leak Suspects Report
2.点击Finish,生成“内存泄露分析报告”
3.从上面的图,我们查看到内存消耗的整体状况
从上面的“内存泄露分析报告”的饼图上,我们可以清晰地看到一个可疑对象消耗了2.3G的内存,占整个系统的98%以上。
4.继续往下看
在图的下方还有对这个可疑对象的进一步描述。我们可以看到内存是由
com.lmax.disruptor.RingBuffer
的实例消耗的,sun.misc.Launcher$AppClassLoader
负责这个对象的加载。
到此,似乎也没找出根本原因(对于新手来说),继续往下看。
5.点击“Details »”,如下图所示
我们发现,产生问题的代码段似乎与log4j有一定关系。
6.进一步定位,查看All Accumulated Objects by Class
里面的内容,如下图
点击消耗Heap最多的First 10 of 524,168 objects
7.查看First 10 of 524,168 objects
里的内容,如下图
看到这里,我们发现是有一个大对象list存放了大量的aaaaaaaaaaa_aaaaaa
的值导致的。
我们通过aaaaaaaaaaa_aaaaaa
在代码上进行搜索,最后发现,原来是下面的代码段导致了这个问题:
String aa = "aaaaaaaaaaaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_aaaaaaaaa_";
List<String> list = new ArrayList();
while (true) {
list.add(aa);
log.info("aa:{}", list);
}
到此,我们非常顺利地完成了一次“Java内存泄漏的排查”。实际上有这个顺利吗?回答是也大概差不多。
PS:我在JVM第一篇:一个Java内存泄漏的排查案例文章中说过下面一段话:
2.2 找出导致频繁Full GC的原因
分析方法通常有两种:
1)把堆dump下来再用MAT等工具进行分析,但dump堆要花较长的时间,并且文件巨大,再从服务器上拖回本地导入工具,这个过程有些折腾,不到万不得已最好别这么干。
2)更轻量级的在线分析,使用“Java内存影像工具:jmap”生成堆转储快照(一般称为headdump或dump文件)。
发现使用Spring Boot Actuator可以推翻一下我上面的一点小误解。
感谢你的阅读,如果对你有帮助就点个赞吧,这样的鼓励会让我更有兴趣写《JVM第三篇:******》