【JVM】分析Dump日志的工具EclipseMAT

发布时间:2026/7/22 2:07:15
【JVM】分析Dump日志的工具EclipseMAT 【JVM】分析Dump日志的工具EclipseMAT【一】初始配置【1】环境配置【2】基础概念【二】各个功能介绍【1】Overview总览面板1Details 概览区2Actions 快捷工具高频使用3Reports 报告区4Inspector 对象详情面板【2】Histogram直方图1打开方式2功能描述3案例4菜单关键选项【3】Dominator Tree支配树定位内存根源持有者1打开方式2功能描述3案例4右键功能【4】Group分组功能【5】Thread Overview【6】List objects1with outgoing references2with incoming references【7】Path to GC Roots Merge Shortets Paths to GC roots1Paths to GC Roots2Merge Shortest Paths to GC roots3菜单选项【8】Leak Suspects Report 泄漏嫌疑自动报告新手一键分析【9】Class Loader Explorer 类加载器专属视图1打开方式2功能描述【10】GC Roots 根路径分析判断对象是否满足 GC 条件【三】使用案例【1】Leak Suspects泄漏嫌疑报告最常用【四】# 关键区分易混淆选项【一】初始配置【1】环境配置1要求JDK version 172heap.hprof文件往往比较大需要修改MemoryAnalyer.ini文件中设置-vmargs-Xmx26g-Xms4g-XX:UseG1GC-XX:UseCompressedOops-XX:MaxGCPauseMillis500-XX:DisableExplicitGC-Dsun.rmi.dgc.client.gcInterval3600000【2】基础概念Shallow Heap浅堆对象本身占用内存不包含引用的其他对象比如DelegatingClassLoader自身对象几十字节。Retained Heap保留堆该对象一旦被 GC 回收能连带释放的全部内存总和判断内存泄漏最核心指标。Histogram直方图按类统计实例数、浅堆、保留堆快速定位数量爆炸类如大量DelegatingClassLoader。Dominator Tree支配树找出占用内存最大的 “罪魁对象”支配对象存活则所有下级对象都无法 GC。Leak Suspects Report泄漏嫌疑报告MAT 自动分析生成的一键诊断报告新手首选。Incoming References入引用谁持有当前对象的强引用你之前 DCL 泄漏最关键视图找阻断 GC 的引用链。Outgoing References出引用当前对象持有哪些其他对象。【二】各个功能介绍【1】Overview总览面板页面分为 4 大区块快速掌握整体内存状态1Details 概览区Heap Sizedump 时总堆内存、已使用内存Number of Objects堆内全部对象总数Class Loaders统计所有类加载器数量直接看有多少 DelegatingClassLoader、RestartClassLoaderUnreachable Objects Histogram已经没有强引用、等待 GC 回收的对象数量大说明内存碎片多。2Actions 快捷工具高频使用表格快捷按钮对应功能适用场景你的 DCL 泄漏场景Histogram直方图视图统计DelegatingClassLoader总实例数、GeneratedMethodAccessor数量Dominator Tree支配树找到 MybatisMybatisConfiguration这个大对象它支配所有反射 Method、DCLTop Consumers内存消耗 TOP 对象查看占用内存最高的单例 BeanSqlSessionFactory、ReflectorFactoryDuplicate Classes重复类检测热部署场景RestartClassLoader重复加载同一 PO 类成倍产生 DCL3Reports 报告区Leak Suspects自动识别内存泄漏点给出完整引用链泄漏嫌疑报告最常用Component Report按 ClassLoader 分组统计单独看 AppClassLoader/DelegatingClassLoader 内存占用Top Components Report超大组件内存分析Mybatis 配置、Spring 容器4Inspector 对象详情面板选中任意对象底部自动展示Class Name类全限定名Shallow/Retained 堆大小字段列表该对象所有成员变量定位reflectorFactory、configuration引用。通过 File Open Heap Dump… 打开dump文件最先展示就是Overview概述界面可以对Heap Dump有一个大致的了解并提供了一些视图、报告的入口这些视图、报告都对分析Heap Dump很有帮助后续会介绍。鼠标移动到饼图某个区域上方在左侧会看到对象的详细信息如左上方的 Inspector 展示了如对象hashcode、类名、包名、Class类对象、父类、类加载器、shallow size、retained size、GC root类型。左下方展示了对象的一些属性信息、类层级信息。【2】Histogram直方图1打开方式以下方式可以打开Histogram柱状图1点击Overview页面Actions区域内的“Histogram视图”链接2点击工具栏的“histogram按钮”2功能描述列含义Class Name类名支持正则搜索DelegatingClassLoader、GeneratedMethodAccessorObjects该类实例总数你最关心的 DCL 数量在这里直接看Shallow Heap所有实例自身占用总内存Retained Heap回收该类所有实例可释放总内存。不过多数情况下在Histogram视图看到实例对象数量比较多的类都是一些基础类型如char[]因为其构成了String、String、byte[]所以仅从这些是无法判断出具体导致内存泄露的类或者方法的可以使用 List objects 或 Merge Shortest Paths to GC roots 等功能继续钻取数据。如果Histogram视图展示的数量多的实例对象不是基础类型是有嫌疑的某个类如项目代码中的bean类型那么就要重点关注了。3案例4菜单关键选项List objects → with incoming references【重中之重】显示所有指向当前对象的强引用链就是你截图里的完整链路GeneratedMethodAccessor → DelegatingMethodAccessorImpl → Method → MethodInvoker → Reflector → DefaultReflectorFactory → MybatisConfiguration用来定位谁锁住 DCL 导致无法 GC元空间泄漏核心操作。List objects → with outgoing references查看当前对象持有哪些下级对象比如查看 Reflector 缓存了多少 Method。Show as Histogram / Show as Pie Chart饼图可视化内存占比直观看到 Mybatis 缓存占用大头。Filter过滤实例数、内存阈值过滤掉小对象只看爆炸增长的类。Merge Shortest Paths to GC Roots一键提取最短 GC 根引用链直接找到 Spring 单例、静态变量、线程等根对象跳过冗长中间链路。Group by → Class Loader按类加载器分组统计区分AppClassLoader、DelegatingClassLoader、热部署 RestartClassLoader清晰看到每个加载器分别创建了多少对象。【3】Dominator Tree支配树定位内存根源持有者支配对象如果 A 对象存活B 对象永远无法被 GC称 A 支配 B。1打开方式以下方式可以打开Dominator Tree视图1点击Overview页面Actions区域内的“Dominator Tree视图”链接2点击工具栏的“Dominator Tree按钮” 为整个堆打开一个支配树视图2功能描述列含义Class Name对象类型Retained Heap该对象支配的总内存Percentage占堆总内存比例。该视图以实例对象的维度展示当前堆内存中Retained Heap占用最大的对象以及依赖这些对象存活的对象的树状结构。视图中展示了实例对象名、Shallow Heap大小、Retained Heap大小、以及当前对象的Retained Heap在整个堆中的占比。点开Dominator Tree实例对象左侧的“”会展示出下一层next level当所有引用了当前实例对象的引用都被清除后下一层列出的objects就会被垃圾回收这也阐明了“支配”的含义父节点的回收会导致子节点也被回收即因为父节点的存在使得子节点存活Dominator Tree支配树可以很方便的找出占用Retained Heap内存最多的几个对象并表示出某些objects的是因为哪些objects的原因而存活在之后的 Dominator Tree概念 部分会对支配树做更详细的说明和举例3案例直接找到根支配对象4右键功能Merge Shortest Paths to GC Roots直达 GC 根Spring 容器Show Retained Set展开所有被该对象锁住的下级对象批量查看所有 DCL 实例。【4】Group分组功能使用Group分组功能的方法是在 Histogram视图 和 Domiantor Tree视图时点击工具栏的 Group result by…可以选择以另一种分组方式显示默认是No Grouping(objects)即以对象维度分组例如在Histogram视图 或 Dominator Tree视图选择Group by package可以更好地查看具体是哪个包里的类占用内存大也很容易定位到自己的应用程序【5】Thread OverviewThread视图的入口在工具栏上Thread Overview在Thread Overview视图可以看到线程对象/线程栈信息、线程名、Shallow Heap、Retained Heap、类加载器、是否Daemon线程等信息在分析内存Dump的MAT中还可以看到线程栈信息这本身就是一个强大的功能类似于jstack命令的效果而且还能结合内存Dump分析看到线程栈帧中的本地变量在左下方的对象属性区域还能看到本地变量的属性真的很方便publicclassTestThreadOverview{privateStringstr1str1;privateStringstr2str2;publicstaticvoidmain(String[]args){TestThreadOverviewtestnewTestThreadOverview();Stringlocal_strlocal_str;LockSupport.park();}}在上面代码的Heap Dump分析中可以看到线程调用栈的信息以及main线程的 本地变量TestThreadOverview 和 字符串local_str 的信息上图中第一个框起来的部分是 new TestThreadOverview()对象代码第6行TestThreadOverview对象有两个属性str1、str2第二个框起来的部分是main方法中的字符串变量local_str代码第8行结合左侧的对象属性区域可以更方便的看清线程中对象的具体情况【6】List objects在 Histogram 或 Dominator Tree视图想要看某个条目对象/类的引用关系图可以使用 List objects 功能1选择一个条目后点击工具栏的 Query Browser List objects选择 with outgoing references 或 with incoming references2直接在某个条目上点击右键也可以选择到List object1with outgoing references查看当前对象持有的外部对象引用在对象关系图中为从当前对象指向外的箭头例如上面Thread Overview的例子代码中查看main方法中第6行中的TestThreadOverview test new TestThreadOverview();outgoing references查询结果为可以看到TestThreadOverview对象存在3个引用第一个是TestThreadOverview的Class类对象因为所有Java类都继承自java.lang.Object所以都有class对象的引用后两个是成员变量str1、str2即列出了当前main方法中的局部变量TestThreadOverview所持有的所有外部对象引用2with incoming references查看当前对象被哪些外部对象所引用在对象关系图中为指向当前对象的箭头例如上面Thread Overview的例子代码中查看main方法中第6行中的TestThreadOverview test new TestThreadOverview();incoming references查询结果为可以看到TestThreadOverview是main线程的一个本地局部变量main线程本身还是一个GC root而main线程在某个ThreadGroup中【7】Path to GC Roots Merge Shortets Paths to GC rootsPath to GC roots 和 Merge shortest Paths to GC roots 的入口和 List objects一样可以从工具栏的 Query Browser 进入或者在条目上直接点击右键进入需要注意的是Paths to GC roots是针对单个对象的故在Histogram视图无法使用因为Histogram视图是针对类的只能使用Merge shortest Paths to GC roots查询1Paths to GC Roots从当前对象到GC roots的路径这个路径解释了为什么当前对象还能存活对分析内存泄露很有帮助这个查询只能针对单个对象使用2Merge Shortest Paths to GC roots从GC roots到一个或一组对象的公共路径3菜单选项Path to GC roots 和 Merge shortest Paths to GC roots 这两个查询都有很多选项如意思是在查询到GC root的路径时是包含所有引用还是排除一些类型的引用如软引用、弱引用、虚引用从GC角度说一个对象无法被GC一定是因为有强引用存在其它引用类型在GC需要的情况下都是可以被GC掉的所以可以使用 exclude all phantom/weak/soft etc. references 只查看GC路径上的强引用【8】Leak Suspects Report 泄漏嫌疑自动报告新手一键分析使用MAT打开一个Dump文件时会弹出向导窗口保持默认选项点Finish就会导向 Leak Suspects内存泄露报告页面MAT 自动扫描 dump把高风险泄漏点分优先级展示分为 3 部分Suspect Summary 泄漏摘要列出 TOP3 嫌疑泄漏点描述问题、预估可释放内存你的 dump 会标记大量GeneratedMethodAccessor被 Mybatis 反射缓存持有导致元空间 ClassLoader 堆积。Suspect Details 详情自动生成精简引用链不用手动逐层展开Comparison Report支持对比两个不同时间的 dump观察哪些类实例持续增长对比前后 dumpDCL 数量持续上涨直接实锤泄漏。功能加载.hprof堆快照文件加载后弹出选择界面Leak Suspects Report默认推荐自动生成泄漏分析报告适合快速排查元空间泄漏、OOM、堆溢出Component Report按业务组件、类加载器分组分析内存取消勾选仅打开空白工作台手动打开 Histogram/Dominator Tree。如果打开Dump时跳过了的话也可以从其它入口进入如1工具栏上的 Run Expect System Test Leak Suspects2Overview页面的Reports部分Leak Suspects 是MAT帮我们分析的可能有内存泄露嫌疑的地方可以体现出哪些对象被保持在内存中以及为什么它们没有被垃圾回收MAT提供了一个很贴心的功能将报告的内容压缩打包到一个zip文件并放在原始堆转储文件的目录下一般命名为“xxx_Leak_Suspects.zip”xxx是dump文件的名字如果需要和同事一起分析这个内存问题的话只需要把这个小小的zip包发给他就可以了不需要把整个堆文件发给他。并且整个报告是一个HTML格式的文件用浏览器就可以轻松打开【9】Class Loader Explorer 类加载器专属视图1打开方式2功能描述按 ClassLoader 树形展示所有加载的类、实例树形分层展示BootClassLoader → ExtClassLoader → AppClassLoader → DelegatingClassLoader统计每个 ClassLoader 加载了多少类、对象、占用元空间右键单个 DelegatingClassLoaderList all Classes查看该加载器加载的所有GeneratedMethodAccessor动态类Show GC Roots查看这个 DCL 被谁强引用判断能否回收。单独筛选所有DelegatingClassLoader实例统计总数区分业务 ClassLoader 和反射专属加载器直观看到 Mybatis 缓存创建了几千个 DCL。【10】GC Roots 根路径分析判断对象是否满足 GC 条件打开方式任意对象右键 →Merge Shortest Paths to GC Roots1GC Roots 类型阻断 DCL 回收的常见根Static Fields静态全局缓存Mybatis DefaultReflectorFactory 是静态单例Thread线程池核心线程、定时任务线程持有上下文 ClassLoaderSystem ClassJDK 系统类ReflectionFactory 全局缓存Local Variable方法内未释放的局部变量长期存活线程的 ThreadLocal。2判断标准对应你之前 DCL GC 三条件若 GC Roots 路径存在业务静态 / 单例 Bean→ DCL 存在永久强引用不满足 GC 条件若仅存在ReflectionFactoryWeakHashMap 弱引用无其他 GC 根 → 满足 GCFull GC 后可回收。【三】使用案例【1】Leak Suspects泄漏嫌疑报告最常用【四】# 关键区分易混淆选项with incoming referencesvswith outgoing referencesincoming谁引用我找泄漏根源必用outgoing我引用谁看缓存存了多少下级对象。Shallow Heap vs Retained HeapShallow对象本身大小无参考价值Retained回收该对象能释放的总内存判断泄漏严重程度。Histogram vs Dominator TreeHistogram按类统计实例数量查 DCL 总数Dominator Tree按单个对象统计支配内存找根单例 Bean。Merge Shortest Paths to GC Roots过滤多层中间无用对象直接展示从 GC 根到目标 DCL 的最短链路简化分析。