Java堆内存溢出本质是对象持续堆积且GC无法回收,排查需按“现象→定位→验证→修复”闭环:先用jstat观察GC行为确认问题,再用jmap获取堆快照,最后用MAT分析泄漏根因,并辅以jstack、Arthas等工具交叉验证。

一、快速确认是不是堆内存 OOM
收到告警(如 CPU 持续 100%、服务响应变慢、日志出现 Java heap space)后,第一步不是 dump,而是验证是否真由堆溢出引发:
- 用 jstat -gc <pid> 1000 实时观察 GC 行为:重点关注 FGC(Full GC 次数)是否突增、FGCT(Full GC 总耗时)是否飙升、O(老年代使用率)是否长期 ≥95%;若 FGC 每分钟几十次且每次耗时数百毫秒,基本可锁定堆内存泄漏。
- 对比 jstat -gcutil <pid> 1000 中 E(Eden)、S0/S1(Survivor)、O(Old)三区使用率:若 Eden 频繁打满触发 YGC,但老年代 O 持续上涨不回落,说明对象过早晋升或长期存活未被回收。
二、获取关键内存快照
确认堆问题后,需捕获现场状态。注意:OOM 后进程可能仍存活(尤其未配置自动 dump 时),jmap 通常仍可执行,但动作要快,避免二次崩溃:
- jmap -heap <pid>:查看当前堆配置(Xms/Xmx)、各代实际大小与使用量,判断是否堆设置过小;
-
jmap -histo <pid>:输出堆中对象数量与总占用字节数排名,快速识别“大户”类(如
byte[]、ArrayList、自定义 DTO 等); -
jmap -dump:format=b,file=/tmp/heap.hprof <pid>:生成完整堆转储文件(hprof),这是 MAT 分析的输入基础;生产环境建议配合
-XX:+HeapDumpOnOutOfMemoryError自动触发,避免人工干预延迟。
三、用 MAT 深度定位泄漏根因
把 hprof 文件拖进 Eclipse Memory Analyzer(MAT),重点看三个视图:
- Leak Suspects Report:MAT 自动生成的初步诊断,直接指出最可疑的泄漏链(如某个静态 Map 持有 80% 对象);
- Histogram:按类统计实例数和浅堆(shallow heap)大小,排序后找到高频大对象类;点击类名 → 右键 “List objects → with incoming references”,查看哪些引用让这些对象无法被回收;
- Dominator Tree:按“支配关系”展示内存占用主干,找出真正 hold 住大量子对象的“父级对象”;再对关键节点右键 “Path to GC Roots”(排除弱/软引用),即可看到从 GC Root(如 static 字段、线程栈局部变量)到该对象的强引用链——这就是泄漏源头。
四、常用辅助工具与验证手段
除核心三件套(jstat/jmap/MAT),以下工具能加速判断或交叉验证:
立即学习“Java免费学习笔记(深入)”;
- jstack <pid>:当怀疑是线程阻塞导致对象堆积(如消费线程卡住、缓存加载线程死锁),可查线程状态与栈帧;
-
Arthas:线上无侵入诊断利器,
dashboard看实时内存、线程、GC;vmtool --action getInstances --className xxx.User直接抽样对象实例;ognl动态调用方法验证缓存状态; - jcmd <pid> VM.native_memory summary(JDK 8u60+):排除堆外内存干扰,确认问题确实集中在堆内;
- VisualVM / JConsole:图形化观察内存曲线、GC 日志趋势,适合初筛与监控比对。


















