MAT分析dump文件显示大小比jmap查询结果小
背景
有朋友向我吐槽,她在一台测试机器上调试,使用jmap查看堆内存占用时,发现年轻代 老年代占用的内存,和dump下堆转储文件使用MAT分析显示的内存不一样,百思不得其解。重现现象如下:
jmap显示堆使用情况
上图为jmap显示的堆使用情况,发现总共占用的内存为,Eden的117M Old的231M=348M。
然而将当前堆内存dump下来,使用MAT打开之后,显示Size为221M?
MAT分析Overview
终究还是不够细心,难道没有看到Details展示中的"Unreachable Objects Histogram"?直接到eclipse翻阅文档,看看什么叫Unreachable Objects(原文在这里)。大致意思是说:
有时一个堆dump文件包含了可能会在下一次GC时被清理掉的对象,站在可达性分析的角度来说,这些对象没有和GC Roots关联,MAT认为它们对于分析内存问题并不重要,所以默认会在解析dump文件时将它们删除。如果dump文件是由OOM时自动产生的,那么其中一般不会包含这些对象,因为JVM通常会执行GC以尝试释放空间;但是也不一定,比如要新分配的对象太大,JVM无法释放足够的空间;或者我们自己手动dump时未使用live参数。
jmap指令
直接点击"Unreachable Objects Histogram"看一下:
这个结果是一个直方图,显示了不可达的对象的类名、对象实例的数量以及它们的总大小。由于不可达的对象在分析dump文件时被删除了,只存储了类名,所以没有对应的对象图表,选定一个class,右键"List objects"也无法查看其引用列表。
处理
要想MAT在分析dump时不删除Unreachable Objects,修改一下配置即可(当然前提是dump文件中本就包含这些对象)。
1、在Window->Preferences->Memory Analyzer中选中"Keep unreachable objects",然后点击"Apply and Close"保存配置:
Window->Preferences->Memory Analyzer
2、关闭已打开的dump文件,×掉就可以了
3、进入Window->Heap Dump History ,选择分析的dump文件,然后右键删除索引文件:Delete Index Files。MAT分析dump后会生成很多索引文件,如果不删除这些文件,MAT就不会重新解析。 可以在这里删除,也可以自行到dump文件所在目录手动删除。
Window->Heap Dump History
4、然后选择File,重新打开dump文件,可以看到Size和预期一致了,不可达的对象没有被删除,然后就可以继续分析了:
Overview
5、选择Open Query Browser->Java Basics->GC Roots
在gc_roots中选中Unreachable栏位,右键选择"Show Retained Set"