标记复制算法通过集中复制存活对象并整块清空来彻底避免内存碎片,核心是将堆分为from/to区顺序复制存活对象、一次性清空原区;依赖高死亡率(如年轻代98%对象快速死亡),采用eden+双survivor三区结构优化空间利用率。

标记复制算法通过“集中复制存活对象+整块清空”来彻底避免内存碎片,核心在于不保留任何零散空闲空间。
内存分配变成顺序写入
复制算法把堆划分为两个等大区域(如 From 和 To),只在其中一块上分配新对象。每次 GC 时,把 From 区所有存活对象按顺序、紧凑地复制到 To 区起始位置。复制完成后,To 区的存活对象是连续排列的,而整个 From 区可被一次性清空——后续分配直接从 To 区当前指针处顺序写入,完全绕开空洞和间隙。
天然消除碎片产生的条件
内存碎片的本质是“已释放但不连续的小块空间”。复制算法不释放单个对象内存,而是整块丢弃原区域;它也不保留死亡对象留下的空隙,而是靠复制动作把所有存活数据“摞成一排”。只要复制完成,可用空间就是一块完整、干净、从头开始的连续区域。
实际落地依赖高死亡率场景
该算法能高效运行的前提是:每次回收时,From 区中绝大多数对象已死亡。JVM 将它用在年轻代正是基于这个事实——新生对象约 98% 在一次 Minor GC 后就不可达。此时只需复制少量存活对象,成本低;若存活率过高(比如老年代),复制开销剧增,反而得不偿失。
代价与折中设计
牺牲一半理论容量是它的硬约束,但 JVM 做了优化:
- 年轻代采用 Eden + 两个 Survivor 的三区结构,不是简单 1:1 对半分,而是 Eden 占大头(如 -XX:SurvivorRatio=8 表示 Eden : Survivor = 8:1:1)
- Survivor 区之间互相复制,Eden 中幸存对象先进 S0,下次 GC 再复制到 S1,始终只用一个 Survivor 承载存活对象
- 当对象在 Survivor 中经历多次复制仍存活,就晋升到老年代——避开复制算法不擅长的高存活率区域
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











