一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

标记-整理算法的压缩阶段原理及其实现

时间:2026-07-13 09:01:46 编辑:袖梨 来源:一聚教程网

标记-整理算法压缩阶段的核心目标是消除内存碎片,通过三步严格序贯操作实现:先计算存活对象新地址并写入forwarding指针,再更新所有引用指向新地址,最后按新地址移动对象数据。

标记-整理算法的压缩阶段,核心目标是消除内存碎片——它不只回收垃圾,还要把所有存活对象“归拢”到堆内存的一端,腾出一大块连续空闲空间。这个过程不是简单清理,而是涉及对象移动、地址重算和引用更新三重操作。

压缩阶段的关键步骤

压缩不是一步到位,而是严格分序执行,避免移动中覆盖或引用错乱:

  • 计算新位置:遍历整个堆,对每个已标记的存活对象,按顺序分配紧邻的新地址(通常从堆底开始),并将其写入对象头的 forwarding 指针中;
  • 更新所有引用:扫描全局(包括栈、寄存器、其他对象字段等),将所有指向原地址的引用,替换成 forwarding 指针所记录的新地址;
  • 实际移动对象:最后才按新地址顺序,把对象数据逐个复制过去——此时因引用已全部更新,不会出现“边搬边用”的冲突。

为什么必须先更新引用再移动?

因为压缩在原堆空间内完成(不依赖额外半区),若先移动对象,而某些引用还指向旧地址,就可能读到被覆盖的脏数据,或导致对象被重复移动。forwarding 指针正是为解耦“定位”与“搬运”而设——它让引用更新有据可依,也使移动可安全延迟。

典型实现:Lisp2 算法

Lisp2 是最经典的标记-压缩实现,其结构清晰体现上述逻辑:

  • 每个对象头预留 forwarding 字段,初始为空;
  • 第一遍扫描填 forwarding(确定去哪);
  • 第二遍扫描更新所有跨对象引用(告诉别人去哪找);
  • 第三遍真正复制对象(按 forwarding 执行搬迁)。

该算法不要求对象大小一致,适用通用 JVM 堆,但需三次遍历,停顿时间相对较高。

压缩带来的实际影响

压缩后堆呈现“存活区 + 空闲区”的整齐格局:

  • 新对象分配只需维护一个指针(如 bump pointer),极快;
  • 不再需要复杂空闲链表管理碎片块;
  • 但移动对象本身开销大,尤其当存活率高、堆巨大时,GC 暂停时间明显延长。

所以 CMS 放弃压缩,G1 则采用分区+局部压缩策略来折中。

热门栏目