首页 > 编程语言 >标记-整理算法压缩阶段原理与实现

标记-整理算法压缩阶段原理与实现

来源:互联网 2026-07-13 07:53:17

标记-整理算法压缩阶段通过计算存活对象新地址写入forwarding指针、更新所有引用、最后按新地址移动对象三步消除碎片。Lisp2算法需三次遍历,移动对象开销大,但分配只需bumppointer,速度飞快。

标记-整理算法的压缩阶段:把碎片“归拢”成整块

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

标记-整理算法压缩阶段原理与实现

标记-整理算法的压缩阶段,本质上是将内存中的碎片彻底清理干净——不仅清除垃圾对象,还要将所有存活对象如同搬家一般,整齐地排列到堆的一端,从而腾出一大块连续的空闲空间。这一过程看似简单,实际操作却涉及对象移动、地址重算和引用更新三重操作,必须严格遵循顺序,否则会导致混乱。

长期稳定更新的攒劲资源: >>>点此立即查看<<<

压缩阶段的关键步骤

压缩操作不能直接移动对象,必须按以下顺序执行,否则可能引发数据错乱:

  • 先计算新地址:从头到尾遍历整个堆,对每个标记为存活的对象,按顺序分配一个紧挨着的新地址(通常从堆底开始),并将该地址写入对象头中的forwarding指针——相当于为每个对象贴上一张“新家地址条”;
  • 再更新所有引用:接着扫描全局范围(包括栈、寄存器、其他对象内的字段),将所有指向旧地址的引用,统一修改为forwarding指针中记录的新地址——让所有“指路牌”都指向正确的新位置;
  • 最后才移动对象:按照新地址的顺序,将对象数据逐一复制过去。此时所有引用已经更新完毕,不会出现“边搬边找”的冲突。

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

因为压缩是在原堆空间内完成的(不依赖额外半区)。如果先移动对象,而某些引用仍指向旧地址,就会读到被覆盖的脏数据,或者导致对象被重复移动。forwarding指针的设计正是为了将“定位置”和“搬东西”这两个步骤解耦——它让引用更新有据可查,也让移动操作可以安全地推迟执行。

典型实现:Lisp2 算法

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

  • 第一遍扫描填充forwarding(确定对象的新地址);
  • 第二遍扫描更新所有跨对象引用(告知其他对象如何找到新地址);
  • 第三遍真正复制对象(按forwarding执行搬迁)。

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

压缩带来的实际影响

压缩之后,堆空间会形成“存活区 + 空闲区”的整齐格局:

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

因此,CMS选择放弃压缩,而G1采用分区加局部压缩的策略来寻求折中——毕竟在性能和延迟之间,需要找到合适的平衡点。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备14008430号-1 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。