模拟内存溢出&通过MAT分析

燃着的半支烟 2020年04月15日 69次浏览

构建一个简单的Springboot应用,模拟出OOM场景,再导出heap dump文件,通过Mat分析。

搭建简易Springboot,模拟OOM场景

搭建一个简易的springboot工程,在controller层循环添加对象,直至OOM。

//循环添加对象,模拟OOM
List<UserVo> userVoListNew = new ArrayList<>();
for (int i = 0; i < 1024 * 1024 * 1024; i++) {
  userVoListNew.addAll(userVoList);
}

具体代码地址,只要本地启动mysql、redis就跑起来了(一般半支烟直接docker启动,方便快捷):https://gitee.com/yclxiao/blog-dbpool/blob/oom/blog-dbpool-main/src/main/java/com/ycl/blog/controller/UserController.java

设置idea & 导出dump文件

1、配置idea的 VM options

在VM options中设置最大内存,以及设置dump文件位置

-Xmx512m
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/Users/yclxiao/Desktop/java_error_in_idea.hprof

image-20200415100749289

2、启动项目

启动项目,swagger调用userController方法,等待OOM出现。最后会在配置的位置上出现java_error_in_idea.hprof文件。

Mat分析dump文件

安装Memory Analyzer

下载地址:https://www.eclipse.org/mat/downloads.php,选择对应的平台安装即可,不需要安装eclipse。

导入dump文件

导入dump文件时,可能碰到以下错误:

An internal error occurred during: "Parsing heap dump from '/Users/yclxiao/Desktop/heapdump-1586847376115.hprof'".
Java heap space

image-20200415105047049

解决方式:修改Applications/mat.app/Contents/Eclipse/MemoryAnalyzer.ini中的最大内存配置

image-20200415104154405

注意:半支烟是mac平台,window平台的文件位置稍微区别,小伙伴们自行查找下,哈哈!

分析dump文件

1、Mat分析概况

导出的dump文件大概400多M,通过MAT分析后,会看到一个饼状图,显示了排名靠前的大对象

image-20200415101642121

2、点击Dominator Tree & Leak Suspects

点击Dominator Tree可以列出最大对象的排名,以及他们持有了哪些对象。点击Leak Suspects可以看到比较有嫌疑的泄露以及系统概述。

image-20200415101855747

3、点击Dominator Tree

可看到最大的Object[],左边显示了他持有的对象,根据这个UserVo我们大概能排查到具体的代码位置。

image-20200415102345372

4、点击Leak Suspects

能大概看到是哪个线程的请求、看到是哪个大对象、看到是哪个具体业务代码,也有堆栈信息,一般根据这些信息能很快定位到有问题的业务代码。

image-20200415102726981

总结

​ 本文介绍了常见的分析OOM的方法。如果碰到线上问题先稳住不要慌,,第一时间保留线程(设置好OOM的dump位置),然后重启服务,再用Mat工具分析问题。

​ 当然啦,问题也可能出现在别的地方,半支烟碰到问题一般是top、df、free这3个命令跑一遍,先看下机器的CPU、硬盘、内存等情况,再做后续分析。

​ 如果更多好建议,欢迎与我交流。