概述
RC Immix 是 合并型引用计数法 + Immix结合.与以往的引用计数法相比,其吞吐量平均提升12%
吞吐量得到改善的原因有两个
-
合并型引用计数法。因为没有通过写入屏障来执行计数器的增减操作,所以即使对象间的引用关系频繁发生变化,吞吐量也不会下降太多
-
撤除了空闲链表。通过以线为单位来管理分块,只要在线内移动指针就可以进行分配了
合并型引用计数法
在合并型引用计数法中要将指针发生改动的对象和其所有子对象注册到更改缓冲区中,等到缓冲区满了,就要运行GC(类似于PHP 的unused队列)
等到GC回收时,才能从缓冲区取出对应的变量进行增量/减量
Immix
ImmixGC 构成
ImmixGC 把堆分为一定大小的块(block), 再把每一个块分成一定大小的线(line). 这个算法不是以对象为单位,而是以线为单位回收垃圾
块最合适的大小是32k字节,线最合适的大小是128字节。每个块就有32 * 1024 / 128 = 256个线
各个块由以下4个域
-
line: 线
-
mark_table: 线对应的标记位串
- FREE(没有对象)
- MARKED(标记完成)
- ALLOCATED(有对象)
- CONSERVATIVE(保守标记)
-
status: 用于表示每个块使用情况的域
- FREE(所有线为空)
- RECYCLABLE(一部分线为空)
- UNAVAILABLE(没有空的线)
-
hole_ctn: 用于表示碎片化严重程度的指标
ImmixGC工作原理
分配时程序首先寻找空的线,然后安排对象。没找到空的线时候就执行GC
GC分为3个步骤执行
- 选定备用的From 块
- 通过hole_ctn数来判断,优先选择碎片化最严重的线作为备用From块
- 判断标准为, “From 块中 ALLOCATED 线和 CONSERVATIVE 线的总数” <= “除From 以外的块中 FREE 线的总数”
- 搜索阶段
- 从根开始搜索对象,根据对象分别进行标记处理或复制处理
- 复制处理指的是将备用 From 块里的对象复制到别的块(To 块/FREE块),并进行压缩
- 清除阶段
- 清除阶段中要搜索各个块的 mark_table
- 如果 mark_table[i] 的值是 ALLOCATED,则设定 mark_table[i] = FREE
合并型引用计数法和Immix融合
RC Immix 中不仅对象有计数器,线也有计数器,这样就可以获悉线内是否存在活动对象
对象的计数器表示的是指向这个对象的引用的数量,而线的计数器表示的是这个线里存在的活动对象的数量
当对象的计数器为 0 时,对线的计数器进行减量操作。当线的计数器为 0 时,我们就可以将线整个回收再利用了
RC Immix 和合并型引用计数法一样,在更改缓冲区满了的时候都会查找更改缓冲区,这时如果发现了新对象,就会把它复制到别的空间(Immix 中的新块)去
同时通过被动碎片整理,对新的对象进行压缩,但是也会导致旧对象碎片化
而积极碎片整理。正好完善无法对旧对象进行压缩、无法回收有循环引用的垃圾的问题。原理就是决定要复制到哪个块,然后把能够通过指针从根查找到的对象全部复制过去