ad

《深入理解 Java 虚拟机 JVM 高级特性与最佳实践(第3版)》_求知之路漫漫_3.3.4 标记-整理算法

网友投稿 65 2023-11-07

【摘要】 本书摘自《深入理解 Java 虚拟机 JVM 高级特性与最佳实践(第3版)》一书中第3章,第3节,周志明著。

3.3.4 标记-整理算法

标记-复制算法在对象存活率较高时就要进行较多的复制操作,效率将会降低。更关 键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的 内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。

针对老年代对象的存亡特征,1974年 Edward Lueders 提出了另外一种有针对性的“标 记-整理”(Mark-Compact) 算法,其中的标记过程仍然与“标记-清除”算法一样,但后 续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向内存空间一端移动, 然后直接清理掉边界以外的内存,“标记-整理”算法的示意图如图3-4所示。

标记-清除算法与标记-整理算法的本质差异在于前者是一种非移动式的回收算法, 而后者是移动式的。是否移动回收后的存活对象是一项优缺点并存的风险决策:

《深入理解 Java 虚拟机 JVM 高级特性与最佳实践(第3版)》_求知之路漫漫_3.3.4  标记-整理算法

这里需要说明一下,HotSpot中的这种分代方式从最初就是这种布局,和IBM的研究并没有什么实际关 系。这里笔者列举 IBM的研究只是为了说明这种分代布局的意义所在。如果移动存活对象,尤其是在老年代这种每次回收都有大量对象存活区域,移动存活 对象并更新所有引用这些对象的地方将会是一种极为负重的操作,而且这种对象移动操作 必须全程暂停用户应用程序才能进行日,这就更加让使用者不得不小心翼翼地权衡其弊端 了,像这样的停顿被最初的虚拟机设计者形象地描述为 “Stop The World”②。

但如果跟标记-清除算法那样完全不考虑移动和整理存活对象的话,弥散于堆中的存 活对象导致的空间碎片化问题就只能依赖更为复杂的内存分配器和内存访问器来解决。譬 如通过“分区空闲分配链表”来解决内存分配问题(计算机硬盘存储大文件就不要求物理连 续的磁盘空间,能够在碎片化的硬盘上存储和访问就是通过硬盘分区表实现的)。内存的访 问是用户程序最频繁的操作,甚至都没有之一 ,假如在这个环节上增加了额外的负担,势 必会直接影响应用程序的吞吐量。

基于以上两点,是否移动对象都存在弊端,移动则内存回收时会更复杂,不移动则内 存分配时会更复杂。从垃圾收集的停顿时间来看,不移动对象停顿时间会更短,甚至可以 不需要停顿,但是从整个程序的吞吐量来看,移动对象会更划算。此语境中,吞吐量的实 质是赋值器 (Mutator, 可以理解为使用垃圾收集的用户程序,本书为便于理解,多数地方 用“用户程序”或“用户线程”代替)与收集器的效率总和。即使不移动对象会使得收集 器的效率提升一些,但因内存分配和访问相比垃圾收集频率要高得多,这部分的耗时增加, 总吞吐量仍然是下降的。HotSpot 虚拟机里面关注吞吐量的Parallel Scavenge 收集器是基于 标记-整理算法的,而关注延迟的CMS 收集器则是基于标记-清除算法的,这也从侧面印 证这点。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们 [email protected] 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:《自己动手写 Python 虚拟机》_更理解虚拟机的意义_6.1.3 调用方法
下一篇:《Python+3自动化软件发布系统》Django 2实战_了解Python的更好方法_2.8.3 ORM常用 Field 及属性
相关文章

 发表评论

暂时没有评论,来抢沙发吧~

×