java gc通过年轻代(eden+s0/s1)与老年代协同实现高效回收:对象优先在年轻代分配,经minor gc复制存活对象并按年龄或动态策略晋升老年代;老年代满时触发标记整理等算法回收,full gc应尽量避免。

Java 的垃圾回收(GC)通过分代模型实现高效管理,核心是年轻代(Young Generation)和老年代(Old Generation)协同工作:对象优先在年轻代分配和回收,存活时间长的逐步晋升到老年代,再由针对性更强的 GC 算法处理。这种分工大幅减少全堆扫描开销,提升吞吐和响应。
年轻代负责快速回收短生命周期对象
年轻代分为 Eden 区和两个 Survivor 区(S0、S1)。新对象一律分配在 Eden;当 Eden 满时触发 Minor GC:
- 扫描 Eden 和当前使用的 Survivor(如 S0),将仍存活的对象复制到另一个空的 Survivor(如 S1)
- 每经历一次 Minor GC,对象年龄 +1;达到阈值(默认 15,可通过 -XX:MaxTenuringThreshold 调整)后,直接晋升至老年代
- 大对象(如长数组)可能直接进入老年代(受 -XX:PretenureSizeThreshold 控制)
- 若 Survivor 空间不足,部分对象也会提前晋升
老年代承载长期存活对象并触发更重的回收
对象晋升到老年代后,不再频繁参与 Minor GC。当老年代空间不足时,触发不同类型的 GC:
- 如果仅老年代满,且年轻代还有空间,JVM 可能先尝试 Minor GC,看能否腾出足够对象晋升空间(避免 Full GC)
- 真正触发老年代回收时,常用算法是标记-整理(如 Serial Old、Parallel Old)或标记-清除+压缩(如 CMS 已废弃,G1/ZGC/Shenandoah 则采用增量或并发方式)
- Full GC 通常意味着整个堆(含年轻代、老年代、元空间)都被扫描,停顿时间长,应尽量避免
两代之间关键配合机制
年轻代与老年代不是孤立运行,而通过多种策略紧密联动:
- 动态年龄判定:不严格依赖年龄阈值。若某 Survivor 中,年龄为 n 的一批对象总大小 > Survivor 空间的一半,则所有 ≥n 的对象直接晋升——防止 Survivor 溢出
- 空间担保机制:Minor GC 前,JVM 检查老年代最大可用连续空间是否 ≥ 年轻代所有对象总大小。若不满足,且设置了 -XX:+HandlePromotionFailure(默认开启),则尝试进行一次 Full GC;否则直接 Full GC
- G1/ZGC 等新收集器弱化代际边界:虽仍逻辑分代,但以 Region 为单位管理,老年代回收可与年轻代交错执行,降低 STW 时间
调优建议:让配合更高效
合理配置参数能让两代协作更顺畅:
- 监控 GC 日志(-Xlog:gc*)重点关注晋升速率、老年代增长趋势和 Full GC 频次
- 年轻代不宜过小(否则 Minor GC 过于频繁),也不宜过大(导致单次 Minor GC 停顿变长);一般设为堆内存的 1/4~1/2
- 适当调整晋升阈值,避免过早晋升(浪费老年代空间)或过晚晋升(Survivor 多次拷贝开销大)
- 对延迟敏感场景,优先选用 G1 或 ZGC,并通过 -XX:MaxGCPauseMillis 等参数引导其行为
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











