MAT的直方图展示了当前dump文件每个类的对象数量、占用的shallow heap 和 retained heap。在直方图这个页面,用户可以做很多的分析操作。
如何进入直方图
鼠标左击工具栏的直方图图标即可进入直方图页面。
最开始Retained Heap是没有计算的,我们可以点击工具栏计算图标计算。有两种选择:
- 计算最小的Retained Size:计算比较快,但是结果是大约的一般是>=某个值;
- 计算精确的Retained Size:计算比较慢,算出来的结果是精确的值。
追踪对象引用的对象(outgoing references)和被引用的对象(incoming references)
在直方图页面选中一行右键弹出菜单,选择"List Objects"。具体操作如下图:
outgoing references追踪的是对象引用的对象,一直到某个不包含引用的对象或者所有引用为NULL的对象。
以io.netty.buffer.PoolSubpage
的某个对象为例,这个对象的bigmap数组变量往下就没有引用了,其chunk对象变量里却还有引用,我们可以一直点下去,看一下对象的引用关系。
incoming references追踪的是对象被哪些对象引用,一直到某个GC Root。同样,我们以io.netty.buffer.PoolSubpage
的某个对象为例
我们发现该对象(0x7523f5188)被两个对象(0x74172d900和0x7462f0820)引用,其中0x7462f0820对象的两个引用(next、pre)都是指向它。
我们继续展开0x7462f0820对象。
是不是很奇怪0x7462f0820对象也同样被0x7523f5188对象的next和pre指向。其实这说明PoolSubpage是一个双向链表结构,且0x7462f0820对象和0x7523f5188对象互相指向,说明这个链表只有2个元素。
outgoing references 和 incoming references对于我们分析对象的来龙去脉很有帮助。用好它我们能知道是哪个类直接导致内存消耗。
Merge Shortest Paths to GC Roots VS. Path to GC Roots
Merge Shortest Paths to GC Roots分析GC Roots到达对象所有路径中最近的一条。这个操作可以从直方图中类点进去,也可以从具体的对象进去。
Path to GC Roots分析对象通向所有GC Roots中所有路径。这个只能从具体的对象进去。
JAVA Basics
1) Class Loader Explorer
列举当前对象或类的类加载器以及该加载器加载的所有的类
2) Find Strings
按正则表达式搜索字符串,就在java.lang.String
的对象里面搜索
3) Group by Value
将对象集根据对象的某个字段进行分组。比方说我们根据java.lang.String
的value字段进行分组,再根据Retained Heap进行排序,能发现当前dump文件中占用空间较大的String。如果这个String值是业务代码(不是框架),那么很有可能存在泄漏
集合操作
集合操作主要有数组或者集合的填充率、按size分组、map的冲突率。
1) 填充率
集合或者数组有两个概念容量和size。容量是集合能装多少,size是实际装了多少。
填充率在0~0.2之间的有6498个,我们继续看这写链表是谁引用,以及里面装了什么数据(实际上虽然数量大但是总的占用空间2M,可以不用分析)。
2) Group by Size
操作结果如下,具体的使用场景还是看情况而论,如果dump文件中集合或者数组比较异常,这样分析一下也许有收获。
3) map的冲突率
冲突率反应的是map中元素hashcode分布情况,冲突率越高说明很多元素的hashcode是一样的。冲突率高并不反应内存使用情况,但它能一定程度反应性能。