新生代适合标记-复制算法,因其对象“朝生夕灭”,每次minor gc约90%以上死亡,仅需复制少量存活对象;内存分配快、无碎片、停顿可控,hotspot通过eden:survivor=8:1:1设计将空间浪费压缩至约10%。

标记复制算法(Mark-Copy)是 Java 垃圾回收中一种经典的年轻代回收策略,核心思想是“空间换时间”:将内存划为两块相等区域,只使用其中一块,当这块快满时,把所有存活对象复制到另一块,再一次性清空原区域。
为什么年轻代适合用标记复制?
因为年轻代对象大多“朝生夕死”,统计表明 90% 以上的对象在 Eden 区经历一次 GC 就不再被引用。复制算法只需遍历并搬运存活对象,无需处理大量死亡对象,效率高、无内存碎片。
- 每次回收只需关注少量存活对象,复制开销小
- 复制后内存天然紧凑,避免了整理或合并的额外成本
- 实现简单,GC 暂停时间(STW)相对可控
HotSpot 中的典型实现:Eden + Survivor
实际 JVM 并非严格“均分两块”,而是采用 Eden : Survivor0 : Survivor1 = 8 : 1 : 1 的比例(可通过 -XX:SurvivorRatio 调整)。一次 Minor GC 流程如下:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 先标记 Eden 和一个 Survivor(如 S0)中所有可达对象
- 将存活对象复制到另一个空的 Survivor(如 S1),同时按年龄+1记录(用于晋升判断)
- Eden 和 S0 全部清空;S1 成为新的“目标 Survivor”,S0 变为空闲区
- 若对象在 Survivor 中熬过一定次数(默认 15,由 -XX:MaxTenuringThreshold 控制),则晋升至老年代
复制失败怎么办?
当 Survivor 空间不足以容纳所有存活对象时,会发生“担保机制(Handle Promotion)”:JVM 直接将部分对象(通常是年龄大或大对象)提前晋升到老年代,甚至触发 Full GC。
- 可通过 -XX:+HandlePromotionFailure 控制是否启用该机制(JDK 7 后默认开启)
- 频繁晋升可能预示 Survivor 太小或对象生命周期异常,需结合 GC 日志分析
- 大对象(如长数组)可能直接分配到老年代(-XX:PretenureSizeThreshold 可设置阈值)
和标记清除、标记整理的区别在哪?
标记复制不适用于老年代——因为老年代存活率高,复制成本太大。所以老年代常用标记清除(CMS)或标记整理(Serial Old / G1 的部分阶段)。
- 标记清除:仅回收死亡对象,留下碎片,可能引发频繁 GC 或分配失败
- 标记整理:回收后移动存活对象,消除碎片,但移动成本高、STW 时间长
- 标记复制:适合低存活率场景,吞吐高、暂停短,但内存利用率只有 50%(理论值,实际因 Survivor 动态调整而略高)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










