Full GC触发原因可直接通过日志括号内关键词(如Ergonomics、System.gc()、Allocation Failure)及老年代内存变化趋势(如GC后Old Usage持续高位或仅微降)精准判断。

看 GC 日志里的括号内容和前后内存变化,就能直接判断 Full GC 触发原因。关键不是记所有类型,而是抓住日志中几个明确的标识词和数字趋势。
看括号里的触发关键词
每条 Full GC 日志开头的括号里会写明原因,这是最直接的线索:
- Full GC (Ergonomics):JVM 自动调优机制认为当前堆配置不合理(比如老年代长期高水位),主动触发回收;常见于堆大小未显式设置、NewRatio 不合理、或 GC 器自动切换失败时
-
Full GC (System.gc()):代码或第三方库调用了
System.gc();需全局搜索项目及依赖 jar 中的该调用 -
Full GC (Metadata GC Threshold) 或日志含
Metaspace allocation failure:元空间不足,多见于大量动态代理(如 Spring AOP)、热部署、频繁定义新类(如 Groovy 脚本、JSON Schema 编译) - Full GC (Allocation Failure):年轻代 Minor GC 后对象晋升老年代,但老年代没空间容纳——这是最常见原因,说明老年代已长期饱和
- concurrent mode failure 或 promotion failed:使用 CMS 收集器时,老年代碎片化或预留空间不足,导致并发收集失败后退化为 Full GC
看老年代内存变化趋势
光看一次日志不够,要连续观察多行,重点对比 [ParOldGen: A->B(C)] 这段:
将后端 Java 接口文档转换为前端 TypeScript 类型定义(interface / type)。输入:飞书文档、Spring Boot 接口文档、Swagger/OpenAPI、手写 API 文档等。输出:包含请求参数与响应结果的 .md 文件,含完整 JSDoc 注释。触发关键词:Java 转 TS、接口转换、生成前端类型、接口文档转 TypeScript、DTO/VO/BO 转 interface、后端文档转前端类型、生成接口类型、类型定义生成。
- 如果每次 Full GC 后 B 值持续上升(比如从 280MB → 295MB → 310MB),且 C(老年代总容量)不变,大概率是内存泄漏
- 如果 B 值每次只下降一点点(比如 349696K→298456K,仅释放约 51MB),而老年代总容量是 349696K,说明释放空间有限,老年代几乎被占满
- 如果 GC 前老年代已接近 100%(如 348234K/349696K ≈ 99.6%),那下一次 Minor GC 晋升就会立刻触发 Full GC
看 Metaspace 和堆外信息
日志末尾的 [Metaspace: X->Y(Z)] 和是否有 OOM 报错也很关键:
- Metaspace 使用量 Y 接近 Z(最大值),且 Y 在多次 Full GC 后不下降,说明类加载器泄漏或元空间配得太小
- 日志中出现
java.lang.OutOfMemoryError: Metaspace,必须加-XX:MaxMetaspaceSize并检查类加载行为 - 有
OutOfMemoryError: Java heap space但老年代未满?可能是直接内存(Direct Buffer)或本地内存问题,需结合jstat -gc和jmap -histo综合判断
结合时间间隔和停顿时间交叉验证
高频 + 长停顿 + 老年代不回落,基本锁定泄漏;低频 + 单次长停顿 + Metaspace 突增,则优先查类加载。
- 每 3–5 秒一次 Full GC,且每次耗时 >2s → 很可能老年代已无法有效回收,需立即 dump 分析
- 某次 Full GC 后 Metaspace 使用量跳涨 30MB 以上,之后稳定在高位 → 检查该时段是否执行了新模块加载、规则引擎初始化等动作
- Full GC 频率与业务操作强相关(如每天上午 9 点准时开始),可回溯该时间点触发的定时任务或批量接口

















