复制算法通过将存活对象集中复制到新空间并整块清空原空间,避免内存碎片且支持指针碰撞式快速分配;因依赖低存活率,故仅适用于新生代。

Java 垃圾回收使用复制算法提升清理效率,核心在于“只处理存活对象”和“内存连续整理”两个设计。它不扫描全堆、不就地清理,而是把少量活对象集中搬走,再整块清空——这大幅缩短停顿时间,特别适合新生代高频短命对象场景。
复制算法怎么避免碎片并加快分配
复制算法把新生代划分为 Eden 区 + 两个 Survivor 区(S0 和 S1),本质就是 From/To 空间的变体。每次 Minor GC 时:
- 只从 Eden 和一个 Survivor(比如 S0)中识别存活对象
- 将这些对象统一复制到另一个 Survivor(S1)中,并按顺序紧密排列
- 复制完成后,Eden 和 S0 内存被整体清空,无需逐个释放或合并空闲块
- 下一次 GC 时角色互换,S1 变为 From,S0 变为 To
因为所有存活对象都紧凑存放,后续 new 对象只需移动指针(bump-the-pointer),分配极快;也彻底消除了内存碎片,避免了标记-清除后因空间不连续导致的大对象分配失败问题。
为什么只在新生代用复制算法
复制算法的效率高度依赖“存活率低”这个前提。新生代对象约 95% 在几次 GC 后就死亡,每次只需搬运 5% 的数据,开销小、收益高。而老年代对象存活率高,若强行复制:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
- 大量对象要反复拷贝,CPU 和内存带宽压力陡增
- 一半空间长期闲置,堆利用率被硬性压低至 50%
- 频繁复制还可能引发跨代引用维护开销(需卡表 Card Table 配合)
所以 JVM 默认仅在新生代(如 Serial、Parallel Scavenge、G1 的 Young GC)采用复制逻辑,老年代则改用标记-整理或混合策略。
实际影响 GC 效率的关键细节
真正让复制算法高效运转的,不只是“搬数据”,还包括几项协同机制:
- 对象年龄晋升控制:Survivor 区中对象每经历一次 GC 年龄+1,达到阈值(如 -XX:MaxTenuringThreshold=15)才进入老年代,防止过早晋升增加老年代压力
- 动态年龄判定:当某次 GC 后,Survivor 中累计大小 ≥ 50% 的对象已满足晋升年龄,JVM 会提前把这批对象一起送入老年代,避免 Survivor 溢出
- 担保机制(Handle Promotion):若 Survivor 空间不足容纳全部存活对象,JVM 会直接把它们“担保分配”到老年代,保证 Minor GC 必然成功
- TLAB(Thread Local Allocation Buffer)支持
这些设计共同确保复制过程稳定、可控、低延迟,而不是简单粗暴地“复制所有存活对象”。

















