线上GC如何排查

发布时间:2026/8/25 11:30:38
线上GC如何排查 摘要排查思路是“先在线定性再离线定量”。先用 jstat 定性再用 jmap -histo 定位嫌疑对象最后用 jcmd 精准 Dump。永远不在生产环境执行 jmap -dump:live 或 jmap -histo:live因为它们会强制触发 Full GC在高并发场景下等同于自杀。尤其是在云原生 Pod 环境下堆转储Dump本身耗时长、文件巨大、难以拉取所以它绝不是首选工具。第一步快速定性——先用 jstat 看整体态势先用 jstat -gcutil PID 1000 10看两个核心指标· FGC 频率如果 FGC 频繁且耗时飙升说明老年代已满可能存在内存泄漏或大对象直接晋升。· YGC 频率如果 YGC 每分钟几十次说明年轻代过小或对象分配过快通过这个快速定性就能判断是“突发流量导致”还是“慢泄漏”从而决定下一步动作。第二步在线取证——用 jmap -histo 锁定嫌疑对象接下来我会执行 jmap -histo PID | head -20不带 :live避免触发 GC。这是一个低风险、秒级返回的操作能直接告诉我们堆里数量最多、占用最大的是哪类对象。这一步的价值在于不需要 Dump 就能锁定 80% 的问题。第三步精准深挖——用 jcmd 抓 Dump 做离线分析决策点什么情况下才去抓 Dump只有在直方图已经锁定某个类但看不清引用链才去抓快照。此时我选用 jcmd PID GC.heap_dump而非 jmap。原因是jcmd对在线业务的影响更小且在堆内存 8G 时STW 时间显著低于 jmap。如果线上堆占用已经飙到 90% 以上建议直接抓完快照立即重启应用“止血”再离线用 MAT 分析。第四步临时止血如果来不及分析如果 Full GC 已经让系统濒临崩溃修复代码来不及我会做两件事先止血· 增大年轻代如堆16G时将 -Xmn 从4G调到8G减少 YGC 频率给对象分配腾出更多空间。· 切换 GC 器从 CMS 切到 G1并设置 -XX:MaxGCPauseMillis50。G1 能自动处理大对象Humongous Region避免大对象直接晋升老年代。第五步根因治理代码层面当 Dump 分析锁定根因后我会从代码层面进行治理。比如如果是某个 SQL 查询导致的大对象我会改为分批次查询避免 ResultSet 一次性拉取全部数据到内存。