mat是专用于离线分析.hprof堆转储文件的诊断工具,非实时监控,适用于oom或full gc后定位内存泄漏,需通过jmap、arthas或jvm参数获取高质量快照,并依overview、histogram、dominator tree三步法精准分析泄漏根因。

MAT(Memory Analyzer Tool)不是实时监控工具,而是专用于离线分析堆转储文件(.hprof)的诊断利器。它不采集指标、不接入应用进程,也不替代 Prometheus 或 Arthas 这类运行时监控手段——它的价值在于:当内存异常已发生(如频繁 Full GC、OOM 后自动生成 dump),你手头有一份快照,MAT 就能帮你精准定位泄漏源头。
怎么拿到一份可用的堆快照
没有合格的 .hprof 文件,MAT 就无从下手。关键不是“能不能导出”,而是“导得准不准、影响小不小”:
-
非紧急场景:用
jmap -dump:live,format=b,file=heap.hprof <pid></pid>,触发一次轻量级 Full GC 后只保留存活对象,更贴近真实泄漏状态 -
服务已卡顿或无响应:加
-F强制模式,jmap -F -dump:live,format=b,file=heap.hprof <pid></pid>,避免因 JVM 暂停导致命令挂起 -
预防性兜底:JVM 启动参数加上
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dumps/,OOM 发生时自动落盘,避免人工介入延误 -
大堆慎用 jmap:超过 4GB 的堆,jmap 全量 dump 可能导致应用长时间 STW;优先考虑 Arthas 的
heapdump --live /tmp/heap.hprof,开销更低
打开 MAT 后第一眼该看什么
别急着点 Leak Suspects——先确认快照本身是否可信:
- 看Overview页顶部的 “Total Heap” 和 “Number of Objects”,对比你预期的业务规模:比如一个普通 Web 应用堆设为 2GB,但显示总堆占用 1.95GB、对象数超 500 万,就要警惕异常膨胀
- 检查GC Roots 数量:正常应用一般几百到一两千;若显示上万,大概率存在 ThreadLocal 泄漏、静态集合未清理、或 JNI 引用未释放
- 留意Class Loader 数量:动态加载类(如 Spring Boot DevTools、OSGi、热更新框架)容易引发 ClassLoader 泄漏;数量持续增长且不回收,是典型信号
- 观察Thread 概况:查看 Retained Heap 最高的线程名,比如
http-nio-8080-exec-xx或自定义线程池名称,它们常是泄漏入口点
三个核心视图,按顺序用
真正揪出泄漏对象,靠的是组合判断,不是单点猜测:
-
Histogram(直方图):按类统计 Retained Heap 排序,找“占比高 + 实例数异常多”的类。例如
java.util.HashMap占 40% 内存,但实例仅 3 个 → 往往是某个 HashMap 被静态持有,内部塞了几万条数据 - Dominator Tree(支配树):比 Histogram 更直接。展开后找 Retained Heap 最大的节点,右键 → “Path to GC Roots” → 勾选 “exclude weak/soft/phantom references”。这条路径就是对象无法被回收的根本原因,通常会暴露 static 字段、缓存容器、监听器注册表等强引用链
- Leak Suspects:MAT 自动分析结果,可作为快速验证。但它依赖启发式规则,有时漏报或误报。务必用 Dominator Tree 交叉验证报告里的引用链是否真实存在于代码中
常见泄漏模式与 MAT 验证线索
多数线上泄漏逃不出这几类,MAT 里有固定痕迹:
-
静态集合类缓存未清理:Histogram 中
java.util.ArrayList或java.util.HashMapRetained Heap 突出;Dominator Tree 顶层出现com.xxx.CacheManager.INSTANCE或类似静态单例 -
ThreadLocal 泄漏:Overview 里线程数稳定但 GC Roots 多;Dominator Tree 中大量
java.lang.ThreadLocal$ThreadLocalMap被线程对象强引用;路径终点常指向 Tomcat 的 worker 线程或自定义线程池 -
监听器/回调未注销:Histogram 中业务监听器类(如
com.xxx.UserEventListener)实例数随请求线性增长;Dominator Tree 显示被 EventBus、Spring ApplicationEventMulticaster 或 GUI 组件持有 - 内部类持外层引用:匿名内部类(如 lambda、new Runnable())意外延长了 Activity、Controller 或 Service 生命周期;Dominator Tree 中该类 Retained Heap 高,路径指向 outer this











