Minor GC 在 Eden 区无足够连续空间时触发,与 Survivor 区、老年代、对象年龄无关;Full GC 可由 Promotion Failure 等多种条件独立触发,常由 Minor GC 连带引发。

Minor GC 什么时候发生?看 Eden 区有没有空间
Minor GC 的触发条件非常直接:新对象尝试分配到 Eden 区,但该区已无足够连续空间。它不关心老年代、元空间或对象年龄——只看 Eden 是否“塞满”。
常见误判点:
- 不是“所有 Survivor 都满了”才触发,而是 Eden 满就触发
- TLAB(线程本地分配缓冲)耗尽后 fallback 到共享 Eden 分配失败,也会触发
- 大对象(>
-XX:PretenureSizeThreshold)直接进老年代,反而可能绕过 Minor GC
示例场景:循环创建短生命周期的 String 或临时 ArrayList,很快填满 Eden,几毫秒内就来一次 Minor GC。
Full GC 的触发路径比想象中多,老年代只是常见入口之一
Full GC 不是“老年代满了才来”,而是多个独立条件任一满足即可能触发。真正容易被忽略的是:它常由 Minor GC “连带引爆”。
典型触发链:
-
Promotion Failure:Minor GC 后,存活对象要晋升老年代,但老年代剩余空间 -
Metaspace OOM:动态生成类(如 Spring AOP、Groovy 脚本、大量反射)撑爆元空间,JVM 必须回收并卸载类 → Full GC -
System.gc()被调用,且未启用-XX:+DisableExplicitGC→ 默认转为 Full GC(哪怕你本意只想清老年代) - G1 出现
Mixed GC跟不上分配速度,或 CMS 发生concurrent mode failure→ 回退到全局 STW 回收
注意:Full GC 一定扫描整个堆(Young + Old + Metaspace),不是 Minor GC 加 Old GC 的简单叠加,它有自己独立的标记-清除/整理流程。
怎么从日志里一眼分清是 Minor 还是 Full GC?别信“Major”这个词
JVM 日志里出现 Major GC 基本是干扰项——它既不是标准术语,也不代表固定行为。不同收集器打的日志含义不同:
- CMS 日志里的
Major GC通常指老年代并发回收阶段失败后退化的 Serial Old 收集,实际等价于 Full GC - G1 日志里几乎不出现
Major GC,取而代之的是G1 Evacuation Pause(Minor)或G1 Full GC - 只要看到日志中包含
Full GC、Pause Full、或明确标注Metaspace/PermGen回收,就是 Full GC - 只提
GC pause (young)、Pause Young、或Eden字样,基本可断定是 Minor GC
建议统一用 -Xlog:gc*:stdout:time,uptime(JDK 10+)或 -XX:+PrintGCDetails(旧版)开启结构化日志,避免被模糊命名误导。
影响范围差异直接决定你该盯什么指标
Minor GC 影响小但高频,关键看是否“失控”:如果单次停顿 > 50ms 或频率 > 1s 一次,说明年轻代太小、对象存活率高,或有隐式大对象晋升。
Full GC 影响大且危险,必须零容忍:
- 一次 Full GC 停顿超过 1s,用户请求大概率超时
- 每小时发生 ≥ 2 次 Full GC,基本意味着内存泄漏或配置严重失当
- 频繁 Metaspace Full GC,优先查类加载器是否未释放、是否用了过度动态代理
真正难排查的,往往是那种“没报错但响应变慢”的情况——背后可能是 Minor GC 频繁导致对象过早晋升,悄悄把老年代撑到临界点,某次 Minor GC 突然触发 Promotion Failure,炸出一次 Full GC。这时候光看 Full GC 日志没用,得倒查前几分钟的 Minor GC 行为和晋升量。

















