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

一、快速确认是不是堆内存 OOM
收到告警(如 CPU 持续 100%、服务响应变慢、日志出现 Java heap space)后,第一步不是 dump,而是验证是否真由堆溢出引发:
- 用 jstat -gc
1000 实时观察 GC 行为:重点关注 FGC(Full GC 次数)是否突增、FGCT(Full GC 总耗时)是否飙升、O(老年代使用率)是否长期 ≥95%;若 FGC 每分钟几十次且每次耗时数百毫秒,基本可锁定堆内存泄漏。 - 对比 jstat -gcutil
1000 中 E(Eden)、S0/S1(Survivor)、O(Old)三区使用率:若 Eden 频繁打满触发 YGC,但老年代 O 持续上涨不回落,说明对象过早晋升或长期存活未被回收。
二、获取关键内存快照
确认堆问题后,需捕获现场状态。注意:OOM 后进程可能仍存活(尤其未配置自动 dump 时),jmap 通常仍可执行,但动作要快,避免二次崩溃:
-
jmap -heap
:查看当前堆配置(Xms/Xmx)、各代实际大小与使用量,判断是否堆设置过小; -
jmap -histo
:输出堆中对象数量与总占用字节数排名,快速识别“大户”类(如 byte[]、ArrayList、自定义 DTO 等); -
jmap -dump:format=b,file=/tmp/heap.hprof
:生成完整堆转储文件(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),以下工具能加速判断或交叉验证:
-
jstack
:当怀疑是线程阻塞导致对象堆积(如消费线程卡住、缓存加载线程死锁),可查线程状态与栈帧; -
Arthas:线上无侵入诊断利器,
dashboard看实时内存、线程、GC;vmtool --action getInstances --className xxx.User直接抽样对象实例;ognl动态调用方法验证缓存状态; -
jcmd
VM.native_memory summary (JDK 8u60+):排除堆外内存干扰,确认问题确实集中在堆内; - VisualVM / JConsole:图形化观察内存曲线、GC 日志趋势,适合初筛与监控比对。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











