Full GC 由明确内存压力或显式操作触发,常见原因包括老年代空间不足、Metaspace 达阈值、System.gc() 调用、大对象分配失败及 CMS 并发失败;排查应先用 jstat 验证现象,再结合 GC 日志分类定位,最后通过 jmap + MAT 分析堆快照聚焦高保留内存对象。

Full GC 不是随机发生的,它由明确的内存压力或显式操作触发。排查频繁 Full GC,关键不是调大堆内存,而是定位“谁在持续占用老年代”或“为什么对象总升不上去又收不回来”。
Full GC 的常见触发条件
以下情况会直接导致 JVM 执行 Full GC:
- 老年代空间不足:Minor GC 后对象晋升到老年代,但老年代剩余空间不够容纳,这是最常见原因
- Metaspace 达到阈值:类加载过多(如热部署、动态代理、Groovy 脚本),元空间满时触发
-
显式调用 System.gc():代码或第三方库中写了
System.gc(),尤其在 RMI、某些监控 SDK 或旧版框架中较常见 -
大对象直接分配失败:对象大小超过
-XX:PretenureSizeThreshold,且老年代无足够连续空间存放 - CMS 收集器并发失败:CMS 在并发标记阶段老年代继续增长,预留空间耗尽,触发降级 Full GC(已逐步淘汰,但仍有存量系统)
快速确认是否真在频繁 Full GC
别一上来就 dump 堆,先用轻量命令验证现象:
- 运行
jstat -gcutil <pid> 2000 5,观察 O 列(老年代使用率)是否持续 >85%,且每次 Full GC 后只下降 1%~2% - 看 FGC 列:若每分钟 ≥1 次,属严重异常;配合 FGCT 列看单次耗时是否超 500ms
- 用
jstat -gccapacity <pid>确认各代实际大小,避免参数没生效却误以为配置合理
从 GC 日志锁定根源类型
开启日志是排查前提(JDK8+ 推荐):-Xlog:gc*:file=/var/log/app/gc.log:time,uptime:filecount=10,filesize=10M
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
根据日志末尾的触发原因分类判断:
立即学习“Java免费学习笔记(深入)”;
- Allocation Failure → 老年代真实空间不足,重点查内存泄漏或对象晋升异常
- Metaspace allocation failure → 类加载问题,查 ClassLoader 是否未释放、是否大量生成代理类
-
Full GC (System.gc()) → 搜索代码和依赖包中是否有
System.gc()调用 - promotion failed / to-space overflow → 新生代对象存活率高、Survivor 区太小或晋升阈值不合理
抓堆快照定位“吃内存”的代码
确认是老年代持续增长后,必须获取现场证据:
- 在老年代使用率 80%~90% 时执行:
jmap -dump:live,format=b,file=heap.hprof <pid>(加live更准,且对业务影响较小) - 用 Eclipse MAT 打开 hprof 文件,打开 Dominator Tree,按 Retained Heap 排序
- 重点关注:
• 占比高的java.util.HashMap、java.util.ArrayList、byte[]、char[]
• 引用链含static字段或ThreadLocalMap的对象
• 自定义缓存类、监听器、连接池、未关闭的流等实例

















