复制算法天然生成连续布局,通过将存活对象顺序复制到to空间并采用指针移动分配,确保目标空间内对象首尾相接、零间隙且分配高效。

复制算法本身不负责“保障”对象连续存储,而是天然生成连续布局——它通过复制动作强制把所有存活对象按顺序紧挨着放进新空间,从而让内存天然连续。
内存被硬性划分为两个等大区域
From 和 To 空间大小固定、彼此隔离,各自是一整块连续内存(比如各 1MB)。这种划分由 JVM 在堆初始化时完成,底层依赖操作系统 mmap 或 Heap 分配器提供连续虚拟地址空间。只要分配成功,From/To 就是各自连续的“内存块”,不是碎片化页表拼凑出来的。
存活对象被顺序复制,不留空隙
GC 触发后,算法不会“删除”单个对象,而是遍历 From 空间,把每个存活对象逐个拷贝到 To 空间起始位置,并持续移动写指针:
- 第一个存活对象 → 放在 To 空间 offset 0 处
- 第二个存活对象 → 紧跟在第一个之后(offset = 前一个 size)
- 依此类推,直到最后一个存活对象落位
这个过程不保留原布局、不跳过空位,结果就是 To 空间里所有对象首尾相接、中间零间隙——物理上连续,逻辑上紧凑。
Delphi 内存管理方面的指导性内容,摘录做成了PDF格式的电子书,本书是从一本Delphi书籍中摘录的内存管理那一章内容,不牵扯其它方面的内容,相对具有针对性。内容涉及遍历内存块、共享内存管理器、第三方内存管理器、Delphi内存管理实现框架、用户调用例程的实现等内容。
分配器靠指针移动实现 O(1) 连续分配
复制完成后,To 空间成为新的活动区。后续新对象分配不再需要查找空闲块,只需:
- 检查剩余空间是否足够
- 把对象写入当前写指针位置
- 指针 += 对象大小
这种“bump-the-pointer”方式能保证新对象也严格落在连续序列末端,延续整体连续性。这也是为什么新生代用复制算法 + TLAB 能做到极快分配。
连续性只存在于单个目标空间内
注意:连续性是局部的、单向的——仅体现在每次 GC 后的 To 空间(即新 From)中。From 空间被整体清空,不维护任何结构;跨 GC 周期的对象地址会变化,但每个周期内,存活对象集合在目标空间中始终连续排列。它不追求跨周期地址稳定,只确保当前可用空间可高效利用。










