MAT查内存泄漏关键看“谁不该活却一直活得好”,先通过Leak Suspects报告识别static、ThreadLocalMap等锚点,再用Dominator Tree按Retained Heap排序定位支配对象,结合Histogram发现数量异常的小对象,最后用Path to GC Roots验证是否被强引用链锁定。

用 MAT 查找内存泄漏的大对象,关键不是“谁占得多”,而是“谁不该活却一直活得好好的”。重点看对象是否被强引用链牢牢拴住,导致 GC 无法回收。
先看 Leak Suspects 报告,快速锁定头号嫌疑
MAT 加载 dump 文件后会自动运行 Leak Suspects。它不是简单统计内存,而是基于支配关系和引用模式识别异常存活对象:
- 报告中红色标出的条目(如 “The class X occupies 72% of the heap”)要优先点开
- 关注描述里是否出现 static 字段、ThreadLocalMap、ListenerList、未注销回调 等典型锚点
- 若提示 “one instance holds 500 MB retained heap”,说明这个单例或缓存容器极可能就是泄漏源头
再查 Dominator Tree,按 Retained Heap 排序找“真大块头”
Dominator Tree 展示的是“谁活着,谁就无法被回收”的支配关系。Retained Heap 大,代表它及其所有被它独占引用的对象总内存高:
- 打开 Dominator Tree → 点击 Retained Heap 列排序 → 拉到最顶部几行
- 重点看:类名是否为自定义业务类(如 CacheManager、DataProcessor)、实例数是否明显异常(比如应为 1 却有 12000 个)
- 右键该行 → “Merge Shortest Paths to GC Roots” 可快速聚合多条路径,避免逐个展开
结合 Histogram 看数量异常,揪出泛滥的“小对象”
有些泄漏不靠单个大对象,而是靠海量小对象堆积(如 DTO、VO、字符串)。Histogram 是发现这类问题最直接的视图:
立即学习“Java免费学习笔记(深入)”;
- 打开 Histogram → 右键 → “Group by Package” 或 “Group by Superclass”
- 按 Objects 列降序 → 找出实例数突兀偏高的类(例如某个 OrderDetailDTO 实例超 80 万)
- 选中该类 → 右键 → “List objects → with incoming references” → 查看哪些容器或静态字段在持续 add 它
最后验证引用链:Path to GC Roots(排除弱/软引用)
数量多、Retained 大,不等于就是泄漏。必须确认它是否被一条纯强引用路径死死绑在 GC Root 上:
- 选中可疑对象(或 Histogram 中的某类实例)→ 右键 → “Path to GC Roots” → 选 “with all references”
- 重点检查路径中是否含:java.lang.ThreadLocal$ThreadLocalMap、static java.util.HashMap、javax.swing.JButton$ListenerList、OuterClass$InnerRunnable
- 如果终点是 java.lang.ref.WeakReference 或 Finalizer,说明设计如此或正在等待回收,不是泄漏


















