堆转储对比是java oom排查的关键动作,需对比基线快照(启动后10分钟)与异常快照(oom前5–10分钟或内存达80%时),借助mat分析objects added、retained size delta及支配树,锁定泄漏源头。

Java OOM排查中,堆转储对比不是可选项,而是关键动作。单次堆转储能告诉你“此刻内存长什么样”,但只有对比不同时刻的堆转储,才能看出“内存是怎么涨起来的”——这才是定位泄漏源头最可靠的路径。
为什么必须做堆转储对比?
内存泄漏的本质是对象本该被回收却持续累积。单张快照里看到大量HashMap或String,无法判断是正常业务峰值还是缓慢泄漏;而两张间隔几分钟甚至几小时的快照,若发现某类实例数、总大小持续线性增长,且Retained Heap同步扩大,就基本锁定问题方向。
选对时机:抓取哪两个时间点?
推荐组合如下:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 基线快照:服务刚启动、负载平稳时(比如上线后10分钟),作为健康参照
- 异常快照:OOM前5–10分钟,或内存使用率持续攀升至80%以上时主动触发
- (进阶)增长快照:若条件允许,可在基线后每15分钟自动采集一份,形成趋势序列
MAT中直接对比两份.hprof文件
Eclipse MAT原生支持堆转储对比,操作简单:
- 打开MAT → File → Compare Heap Dumps → 选择两个.hprof文件
- 系统自动生成差异报告,重点看“Objects added”和“Objects retained”两列
- 点击新增对象最多的类(如ArrayList、Byte[]),再右键 → “Merge Shortest Paths to GC Roots” → 查看哪些引用链在新快照中才出现
- 特别关注“retained size delta”值大的类,它代表该类型在两次快照间多占了多少可释放内存
结合直方图与支配树交叉验证
对比结果只是起点,需进一步深挖:
- 在差异视图中双击某个可疑类 → 进入其对象列表 → 右键任一实例 → “Show Retained Set”
- 切换到支配树(Dominator Tree)→ 按Retained Heap排序 → 找出Top 3“新增支配者”
- 检查这些支配者的GC Roots路径,尤其留意static字段、ThreadLocal、缓存容器等常见泄漏锚点
- 若发现某Service类的静态Map不断扩容,再回到代码确认是否漏写了remove逻辑
避免踩坑的实操提醒
对比分析容易忽略但影响结论的细节:
- 确保两次堆转储使用相同JDK版本和GC算法(如都是G1),否则对象布局可能不同,导致误判
- 不要对比Full GC前后的快照——因为堆转储默认在Full GC后生成,内容已过滤掉可回收对象
- 若用jmap生成,加-f参数强制完整转储;用jcmd更稳妥,命令为:
jcmd <pid> VM.native_memory summary</pid>+jcmd <pid> VM.native_memory detail</pid> - 生产环境慎用自动HeapDumpOnOutOfMemoryError配合对比——OOM时刻的快照往往已严重失真,优先用定时采样
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










