核心是定位强引用持有者,而非猜测代码错误:用MAT的Path to GC Roots(排除弱/软引用)查看最短路径,结合Dominator Tree找高Retained Heap的“挡路者”,并用VisualVM OQL或LeakCanary辅助验证典型泄漏模式。

分析内存对象的引用链路径,核心是定位“谁在强持有它”,而不是猜哪个类写错了。关键不在堆里有多少对象,而在于这些对象为什么不能被回收。
用 MAT 查“到 GC Roots 的最短路径”
这是最直接、最常用的手段。打开 .hprof 文件后:
- 在 Histogram(直方图)中筛选你的业务类(如 OrderService、MyActivity),右键任一实例
- 选择 Merge Shortest Paths to GC Roots → 勾选 exclude weak/soft references
- 重点看路径中是否出现 static field、java.lang.Thread、Handler、ThreadPoolExecutor$Worker 或 this$0
如果路径终点是 java.lang.System@12345 或 java.lang.ApplicationClassLoader,说明它被系统级静态容器钉住了;如果中间有 OuterClass$1 → this$0 → OuterClass,基本就是匿名内部类泄漏实锤。
看支配树(Dominator Tree)找“挡路者”
支配树能快速识别真正“卡住内存”的对象——它自己占得多,还拦着下游一堆对象无法释放:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 切换到 Dominator Tree 标签页,按 Retained Heap 降序排列
- 展开顶层大对象,逐层下钻,观察引用关系,例如:CacheManager → cacheMap → Entry → value → BigReportData
- 若发现某 ThreadLocalMap 或 static final ConcurrentHashMap 占据高位,且其 value 是业务对象,大概率就是泄漏源头
用 VisualVM 的 OQL 精准过滤可疑引用
当怀疑某类被特定结构持有时,OQL 可跳过手动翻找:
- 查所有非空的 ThreadLocal 值:select x from java.lang.ThreadLocal$ThreadLocalMap$Entry x where x.value != null
- 查某个类的所有实例及其直接引用者:select * from com.example.UserSession s where s.@referers.size > 0
- 结合结果再点开具体实例,右键 “References” 查它被谁直接引用,比盲扫高效得多
结合 LeakCanary 快速验证典型模式
在 debug 包集成 LeakCanary 后,复现操作几秒内就能弹出泄漏报告:
- 报告会直接标出引用链截图,例如:MainActivity → MyFragment$1 → handler → MessageQueue → Looper → Thread
- 重点关注 “Leaking Activity/Fragment” 和 “Shortest path to GC Roots” 两栏
- 它不代替 MAT,但能帮你快速确认是不是常见模式(如非静态 Handler、未移除监听器),省去前期排查时间

















