深入探索JVM垃圾回收:ARM服务器垃圾回收的挑战和优化
上QQ阅读APP看书,第一时间看更新

2.3.3 标记压缩算法

标记清除算法的内存利用率虽然比较高,但是有一个重要的缺点:内存碎片化严重。内存碎片化可能会导致无法满足应用大内存块的需求。另外一种GC算法是标记压缩算法,其本质是就地压缩内存空间,而不是像复制算法那样需要一个额外的空间。算法可以分为以下4步:

1)遍历内存空间,标记内存空间的活跃对象。

2)遍历内存空间,计算所有活跃对象压缩后的位置,“压缩后”是指如果遇到死亡对象,则直接将其覆盖。

3)遍历内存空间,更新所有活跃对象成员变量压缩后的位置。

4)遍历内存空间,移动所有活跃对象到第二步计算好的位置,此时由于对象内部的成员变量已经完成更新,因此移动对象后所有的引用关系都是正确的。

在一些实现中,第二步和第三步可以借助额外的数据结构合并成一步。总体来说,标记压缩算法需要遍历3~4次内存空间,虽然内存利用率更高,并且GC执行后不存在内存碎片的问题,但是因为多次遍历内存空间,故算法的执行效率不高。

仍然以图2-4的内存状态为例,标记压缩算法执行结束后的示意图如图2-9所示。

图2-9 标记压缩算法执行后内存示意图

由于标记压缩算法执行效率不高,因此通常作为GC的兜底算法。标记压缩在JVM中也有多种实现,分别是串行实现、并行实现。在第3~5章中都会介绍标记压缩算法。