频繁Full GC是系统报警,需按“确认现象→分析日志→抓堆快照→验证代码”四步定位:先用jstat看O、FGC、M列趋势;再查GC日志中Allocation Failure等线索;然后轻量dump存活堆并用MAT分析Dominator Tree和Histogram;最后用Arthas等工具运行态验证静态集合、ThreadLocal及资源泄漏。

频繁 Full GC 不是参数调优问题,而是系统在报警——说明老年代持续承压、对象回收失效,甚至已开始影响可用性。定位根本原因必须按“确认现象→分析日志→抓堆快照→验证代码”四步推进,不能跳步、不能猜。
第一步:用 jstat 快速确认是不是真问题
执行:jstat -gcutil <pid> 1000 10,每秒输出一次,连看 10 秒。重点关注三列:
- O(Old Used):老年代使用率是否单向爬升?GC 后只降 2%~5%,且连续多次不回落 → 指向内存泄漏
- FGC:每分钟 ≥1 次即属严重;若和 YGC 比值接近 1:1 或倒挂,说明大量对象活过多次 Young GC 直接进老年代
- M(Metaspace):持续上涨逼近 100% → 类加载泄漏,不是堆内对象问题
第二步:查 GC 日志锁定触发类型
日志必须提前开启(JDK8+ 推荐:-Xlog:gc*:file=gc.log:time,uptime:filecount=10,filesize=10M)。关键看三类线索:
- 日志中出现 Allocation Failure → 老年代真实空间不足,需结合堆快照查谁占了内存
- 出现 Metaspace allocation failure → 元空间满,重点查动态代理、Groovy 脚本、反复 redeploy
- 出现 Full GC (System.gc()) 或 (Metadata GC Threshold) → 代码或框架显式触发,或元空间自动扩容失败
第三步:抓轻量堆快照,聚焦存活对象
别一上来就 jmap -dump 硬抓。优先用安全方式:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 低峰期执行:jmap -dump:live,format=b,file=heap.hprof <pid>(加 live 参数只导存活对象,STW 时间短、文件小)
- 或提前埋点:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/dumps/,等 OOM 自动触发
用 MAT 打开后,重点看两个视图:
- Dominator Tree:按 Retained Heap 排序,找前三名大对象 → 右键 “Path to GC Roots”,确认是否被 static、ThreadLocal、监听器意外强引用
- Histogram:找实例数暴增的类(如 HashMap$Node、ArrayList、自定义缓存实体)→ 对该类 “List objects” → 查每个实例的 GC Roots 路径
第四步:运行态验证典型泄漏模式
有些问题堆 dump 看不出,必须结合运行中行为确认:
- 用 Arthas 查静态集合:watch com.xxx.CacheService put '{params,returnObj}' -n 10,看是否持续写入未清理
- 查 ThreadLocal 泄漏:ognl '@java.lang.Thread@currentThread().threadLocals',检查 key 是否为已卸载类,value 是否为大对象
- 查资源泄漏:全局搜索 new Socket()、Connection、InputStream,确认是否都在 try-with-resources 或 finally 中 close

















