Minor GC 与 Full GC 动态协作:Minor GC 频繁清理年轻代,Eden 满即触发;Full GC 在晋升前检查失败、担保失败或元空间耗尽等场景主动介入,保障整体堆可用。

分代收集模型中,Minor GC 和 Full GC 不是孤立运行的,而是按对象生命周期和内存压力动态协作的。它们共同构成 JVM 垃圾回收的主干流程,核心逻辑是:Minor GC 为主力清道夫,负责高频清理年轻代;Full GC 是兜底机制,在年轻代无法独立完成回收时介入,保障整体堆可用。
Minor GC 是默认启动入口
几乎所有对象都先分配在 Eden 区。一旦 Eden 空间不足(例如新对象无法放入),JVM 立即触发 Minor GC。它不检查老年代,也不等待 Survivor 满——只看 Eden 是否“写不下”。这个动作快速、轻量,目标明确:腾出 Eden 空间继续分配。
- 存活对象优先复制到空的 Survivor 区(S0 或 S1)
- 年龄达阈值(默认 15)或 Survivor 空间不足时,对象直接晋升老年代
- 整个过程会暂停应用线程(STW),但通常仅几毫秒
Full GC 在关键节点介入协作
Full GC 并非“等老年代满了才出手”,而是在 Minor GC 执行过程中发现风险时提前响应。它的触发不是被动等待,而是对 Minor GC 后续可行性的主动校验。
- 晋升前检查:Minor GC 开始前,JVM 估算本次可能晋升到老年代的对象总大小;若老年代剩余连续空间小于该估算值,直接触发 Full GC(而非先做 Minor GC)
- 担保失败兜底:即使开启空间分配担保(-XX:+HandlePromotionFailure),若晋升时老年代真不够用,仍会抛出 Promotion Failed 并触发 Full GC
- 大对象直入老年代失败:一个超大数组尝试直接分配进老年代,但老年代碎片化或空间不足,也会跳过 Minor GC 直接走 Full GC 流程
老年代与年轻代的容量关系决定协作节奏
两代空间不是静态割裂的。JVM 会根据历史晋升数据动态调整行为。例如:
- 如果过去几次 Minor GC 平均晋升 80MB,而老年代只剩 60MB 连续空间,下一次 Minor GC 就大概率被拦停,转为 Full GC
- Survivor 区过小(如 -XX:SurvivorRatio=12 导致仅占年轻代 1/14),大量对象被迫早晋老年代,加速老年代填充,间接提高 Full GC 频率
- 使用 G1 收集器时,“混合 GC”本质是 Minor GC + 部分老年代 Region 回收的协作变体,Full GC 则是混合 GC 失效后的最终手段
方法区与显式调用带来的跨域联动
Full GC 的协作范围还延伸到非堆区域:
- 元空间(Metaspace)耗尽时,卸载类需回收其关联的堆内对象(如常量池引用的字符串),这会连带触发老年代扫描,所以也走 Full GC 流程
- System.gc() 调用本身不强制 Full GC,但 HotSpot 默认策略是将其转为一次 Full GC 请求;若此时老年代尚宽松,也可能退化为仅清理老年代(Major GC),但现代 JDK 多数实现仍以 Full GC 响应

















