前言
接触项目多多少少会碰到各种问题,OOM就是最常见的一种,记得在维护社科联项目的时候就经常碰到,而当时处理的方式也是非常的暴力,就是简单修改 JVM -Xmx和 -Xms的值,然后写了一个脚本让服务在凌晨的时候重启。这算是应急措施,要想真正解决该问题还是学会分析OOM出现的原因,然后解决。这里记录一次OOM处理状况。
MAT分析
当时OOM的状况已经重现不了,所以这里就模拟当时的一个场景,然后分析是如何通过MAT来排除问题的。MAT是eclipse的插件,关于它的安装网上有很多,这里不复述了。以下代码来模拟内存溢出。
1 |
|
设置JVM运行参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
。发生异常后生产的dump文件的默认名称为”java_pid进程id.hprof”,默认生成路径为工程的根目录。
使用MAT打开生成的hprof文件,最先展示就是Overview概述界面,可以对Heap Dump有一个大致的了解,并提供了一些视图、报告的入口。
基本上Overview的概述是不能清楚知道具体是什么问题,需要点击查看Histogram(柱状图)视图和Dominator Tree(支配树)视图。
Histogram 视图
Histogram视图在上图标注1可以点开,打开后如下图:
从Histogram视图可以看出,哪个Class类的对象实例数量比较多,以及占用的内存比较大。
Shallow Size是对象本身占据的内存的大小,不包含其引用的对象。对于常规对象(非数组)的Shallow Size由其成员变量的数量和类型来定,而数组的ShallowSize由数组类型和数组长度来决定,它为数组元素大小的总和。
Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。可以在下面看到对两者的对比。
不过,多数情况下,在Histogram视图看到实例对象数量比较多的类都是一些基础类型,如char[](因为其构成了String)、String、byte[],所以仅从这些是无法判断出具体导致内存泄露的类或者方法的,如果Histogram视图展示的数量多的实例对象不是基础类型,是有嫌疑的某个类,如项目代码中的bean类型,那么就要重点关注了。比如下图我们可以看到自定义bean占用了很大的内存,那么这个类很有可能就是突破口了。
Dominator 视图
如果在Histogram并不能发现什么,可以从Dominator 视图入手(点击Histogram视图旁边的按钮)。如下图中,我们可以看到java.lang.Thread Shallow Heap只占了120个字节大小,但是它Retained Heap引用到的对象却有7203584个字节,通常这种对象都是要怀疑的对象。
在怀疑的对象上右键选择到List object:
List objects –> with outgoing references:查看当前对象持有的外部对象引用(在对象关系图中为从当前对象指向外的箭头)
List objects –> with incoming references:查看当前对象被哪些外部对象所引用(在对象关系图中为指向当前对象的箭头)
查看它的 outgoing references 发现它的引用对象中占最大比例的是OOMObject,由此也能发现可疑的对象。这个时候和开发人员沟通一下看看可疑对象在哪些地方使用的不恰当,一般能解决掉。
社科联项目OOM原因
当时记得是管理员要添加一块功能,具体是将所有项目成员的所有信息都打印到Excel中,设计到了表的关联查询,导致存放的hashMap对象够大,而且这个HashMap是一个static类变量,没能及时的回收导致内存溢出。
参考文章
MAT使用详细解析,解析的很好
https://www.cnblogs.com/trust-freedom/p/6744948.html
真实实例分析
https://blog.csdn.net/nielinqi520/article/details/78455614