「垃圾回收的算法和实现」 第六章-保守式 GC

Posted by Dawn-K's Blog on January 26, 2022

保守式 GC

背景

保守式 GC 并不是一种算法。而是要针对之前的一些问题进行更现实的讨论。

比如我们之前的所有判断都基于一点,就是算法本身能直接分辨出一个域是指针还是其他类型。这个实际上是不一定的。我们可以假设一种语言,这种语言本身没有 gc,gc 只是作为一个附加库存在的,gc 面对内存时,只能看见一个一个的字节。

在这种情况下,普通类型是很容易被误认为指针的。比如前文复用对象的域的 forward。换言之也就是根不明确了.

保守式 GC 是说,通过几个简单的规则排除掉指针之后,剩下的只要可能指向堆中某个对象的元素我们都认为是指针,也就是宁可少回收一些垃圾,也不误回收一个。

  1. 是不是正确被对齐的值(32 位机上是 4 的倍数)
  2. 是不是指向堆内
  3. 是不是指向对象的开头

第三条主要是之前提到的 BiBop 法

这样的话就不需要语言级别的支持,但是有两个致命缺陷

  1. 对堆内存使用不充分
  2. 能使用的 GC 算法有限,因为保守,所以所有能挪动对象的 GC 算法都没法使用。

准确式 GC

为了识别准确的根,有一个简单的方法,但是需要语言处理系统的支持。就是我们利用指针的后两位都是 0 的特性,对于所有数字,我们都左移一位,然后最右边置 1(x«1 1), 如果溢出就换大一号的类型来存。

这样我们只需要看最后一位了,如果是 1 就是数字,否则就是 0. 这一个技巧也可以用来实现前文提到的 tag 之类的操作。总之就是多了一位存储空间。

准确式 GC 的优点在于能够充分利用堆空间,每次都能清理干净。缺点是必须有语言处理的支持,而且会导致运行缓慢。

句柄引用

这个方法的思路在于,不直接让根指向对象。让根指向一个对象句柄(可以理解为一个指针数组)根指向其中的元素,元素又指向对象。就可以把根和对象解耦,如果对象的位置修改了,就不需要修改根本身了。

这种方法就可以使用所有的 GC 回收算法了,但是依旧是拖慢了运行速度(因为多了一层引用)

后面还有个 MostlyCopingGC,累了,鸽了。