1.前言
熟练掌握MAT是Java高手的必备能力,但实践时大家往往需面对众多功能,眼花缭乱不知如何下手,小编也没有找到一篇完善的教学素材,所以整理本文帮大家系统掌握MAT分析工具。
本文详细讲解MAT众多内存分析工具功能,这些功能组合使用异常强大,熟练使用几乎可以解决所有的堆内存离线分析的问题。我们将功能划分为4类:内存分布详情、对象间依赖、对象状态详情、按条件检索。每大类有多个功能点,本文会逐一讲解各功能的场景及用法。此外,添加了原创或引用案例加强理解和掌握。
如图所示:
为减少对眼花缭乱的菜单的迷茫,可以通过下图先整体熟悉下各功能使用入口,后续都会讲到。
2.内存分布详解及实战
2.1全局信息概览
功能
:展现堆内存大小、对象数量、class数量、classloader数量、GCRoot数量、环境变量、线程概况等全局统计信息。
使用入口
:MAT主界面→HeapDumpOverview。
举例
:下面是对象数量、classloader数量、GCRoot数量,可以看出classloader存在异常。
举例
:下图是线程概况,可以查看每个线程名、线程的RetainedHeap、daemon属性等。
使用场景
全局概览呈现全局统计信息,重点查看整体是否有异常数据,所以有效信息有限,下面几种场景有一定帮助:
方法区溢出时(Java8后不使用方法区,对应堆溢出),查看class数量异常多,可以考虑是否为动态代理类异常载入过多或类被反复重复加载。
方法区溢出时,查看classloader数量过多,可以考虑是否为自定义classloader被异常循环使用。
GCRoot过多,可以查看GCRoot分布,理论上这种情况极少会遇到,笔者只在JNI使用一个存在BUG的库时遇到过。
线程数过多,一般是频繁创建线程但无法执行结束,从概览可以了解异常表象,具体原因可以参考本文线程分析部分内容,此处不展开。
2.2Dominatortree
注:笔者使用频率的Top1,是高效分析Dump必看的功能。
功能
展现对象的支配关系图,并给出对象支配内存的大小(支配内存等同于RetainedHeap,即其被GC回收可释放的内存大小)
支持排序、支持按package、classloader、superclass、class聚类统计
使用入口
:全局支配树:MAT主界面→Dominatortree。
举例:
下图中通过查看Dominatortree,了解到内存主要是由ThreadAndListHolder-thread及main两个线程支配(后面第2.6节会给出整体案例)。
使用场景
开始Dump分析时,首先应使用Dominatortree了解各支配树起点对象所支配内存的大小,进而了解哪几个起点对象是GC无法释放大内存的原因。
当个别对象支配树的RetainedHeap很大存在明显倾斜时,可以重点分析占比高的对象支配关系,展开子树进一步定位到问题根因,如下图中可看出最终是SameContentWrapperContainer对象持有的ArrayList过大。
在Dominatortree中展开树状图,可以查看支配关系路径(与outgoingreference的区别是:如果X支配Y,则X释放后Y必然可释放;如果仅仅是X引用Y,可能仍有其他对象引用Y,X释放后Y仍不能释放,所以Dominatortree去除了incomingreference中大量的冗余信息)。
有些情况下可能并没有支配起点对象的RetainedHeap占用很大内存(比如classX有100个对象,每个对象的RetainedHeap是10M,则classX所有对象实际支配的内存是1G,但可能Dominatortree的前20个都是其他class的对象),这时可以按class、package、classloader做聚合,进而定位目标。
下图中各GCRoots所支配的内存均不大,这时需要聚合定位爆发点。
在Dominatortree展现后按class聚合,如下图:
可以定位到是SomeEntry对象支配内存较多,然后结合代码进一步分析具体原因。
在一些操作后定位到异常持有RetainedHeap对象后(如从代码看对象应该被回收),可以获取对象的直接支配者,操作方式如下。
2.3Histogram直方图
注:笔者使用频率Top2
功能
罗列每个类实例的数量、类实例累计内存占比,包括自身内存占用量(ShallowHeap)及支配对象的内存占用量(RetainHeap)。
支持按对象数量、RetainedHeap、ShallowHeap(默认排序)等指标排序;支持按正则过滤;支持按package、classloader、superclass、class聚类统计,
使用入口
:MAT主界面→Histogram;注意Histogram默认不展现RetainedHeap,可以使用计算器图标计算,如下图所示。
使用场景
有些情况Dominatortree无法展现出热点对象(上文提到Dominatortree支配内存排名前20的占比均不高,或者按class聚合也无明显热点对象,此时Dominatortree很难做关联分析判断哪类对象占比高),这时可以使用Histogram查看所有对象所属类的分布,快速定位占据RetainedHeap大头的类。
使用技巧
Integer,String和Object[]一般不直接导致内存问题。为更好的组织视图,可以通过classloader或package分组进一步聚焦,如下图。
Histogram支持使用正则表达式来过滤。例如,我们可以只展示那些匹配com.q.*的类。
可以在Histogram的某个类继续使用outgoingreference查看对象分布,进而定位哪些对象是大头
2.4LeakSuspects
功能
:具备自动检测内存泄漏功能,罗列可能存在内存泄漏的问题点。
使用入口
:一般当存在明显的内存泄漏时,分析完Dump文件后就会展现,也可以如下图在MAT主页→LeakSuspects。
使用场景
:需要查看引用链条上占用内存较多的可疑对象。这个功能可解决一些基础问题,但复杂的问题往往帮助有限。
举例
下图中LeakSuspects视图展现了两个线程支配了绝大部分内存。
下图是点击上图中Keywords中"Details",获取实例到GCRoot的最短路径、dominator路径的细信息。
2.5TopConsumers
功能
:最大对象报告,可以展现哪些类、哪些classloader、哪些package占用最高比例的内存,其功能Histogram及Dominatortree也都支持。
使用场景
:应用程序发生内存泄漏时,查看哪些泄漏的对象通常在Dump快照中会占很大的比重。因此,对简单的问题具有较高的价值。
2.6综合案例一
使用工具项
:Heapdumpoverview、Dominatortree、Histogram、ClassLoaderExplorer(见3.4节)、incomingreferences(见3.1节)
程序代码
packagecom.q.mat;importjava.util.*;importorg.objectweb.asm.*;publicclassClassLoaderOOMOpsext
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.