Java内存泄漏排查应分层递进:先用jstat -gcutil实时监控老年代使用率、Full GC次数及耗时,确认泄漏存在;再执行jmap -histo:live定位实例数与内存占用异常增长的业务类;最后用jmap -dump:live导出快照,结合MAT分析GC Roots引用链。

Java 内存泄漏排查不依赖复杂平台,JDK 自带的几个命令行工具就能快速定位问题。关键不是一上来就 dump 堆,而是分层递进:先看 GC 行为是否异常,再找膨胀类,最后导出快照分析引用链。
jstat:实时观察 GC 异常,判断泄漏是否正在发生
它是第一响应工具,开销极低、无需暂停应用。常用命令:
-
jstat -gcutil <pid> 1000:每秒刷新一次,重点关注三列
— O 列(Old Gen 使用率):持续上升且不回落(如从 30% 涨到 98% 卡住)
— FGC 列(Full GC 次数):短时间猛增(2 分钟内从 0 到 12)
— FGCT 列(Full GC 总耗时):逐次变长,同时 YGC 频次可能同步升高 - 只要 O 持续涨 + FGC 频繁 + FGCT 变长,基本可确认存在活跃泄漏
jmap -histo:快速锁定可疑膨胀类
确认泄漏后立即执行,只统计存活对象,避免死亡对象干扰:
-
jmap -histo:live <pid> | head -n 20
— 关注 #instances 和 #bytes 都靠前的类,尤其是业务包路径下的类(如 com.example.UserCache)
— 注意常见数组类型:[C(字符串)、[[I(二维 int 数组)、[Ljava.lang.Object;(Object 数组,常出现在集合扩容中) - 若某类实例数每分钟增长数千,而请求量无对应变化,大概率就是泄漏源头
jmap -dump:导出轻量级堆快照供 MAT 分析
定位到可疑类后,导出仅含存活对象的快照,体积小、分析快:
立即学习“Java免费学习笔记(深入)”;
-
jmap -dump:live,format=b,file=leak-$(date +%s).hprof <pid>
— 必须加 live 参数,确保只导出可达对象
— 文件名带时间戳,方便后续比对多个快照的变化趋势 - 导出后用 MAT 打开 → 运行 “Leak Suspects Report” → 查看 Dominator Tree → 追踪 “Path to GC Roots”
— 重点检查 static 字段、ThreadLocal、未注销监听器、内部类隐式引用等强引用路径
jinfo:交叉验证 JVM 启动参数,排除配置干扰
有些内存问题表面像泄漏,实则是参数不合理导致的假象:
-
jinfo -flags <pid>:检查是否启用自动 dump
— 若未开 -XX:+HeapDumpOnOutOfMemoryError,建议补上,下次 OOM 自动留证据 -
jstat -gcmetacapacity <pid>:查看元空间使用率
— M 区长期 >90%,可能是类加载泄漏(如热部署未清理旧类) - 检查 -Xms/-Xmx 是否差距过大,或 -XX:NewRatio 是否导致老年代初始过小,掩盖真实泄漏节奏


















