缘由
增量式垃圾回收是一种通过逐渐推进垃圾回收来控制mutator最大暂停时间的方法。增量式垃圾回收是将GC和mutator一点点交替运行的手法。
三色标记算法
Dijkstra等人提出的概念,按照各自的情况将对象分成三种
白色:还未搜索过的对象
灰色:正在搜索的对象
黑色:搜索完成的对象
算法描述
GC开始运行前所有的对象都是白色。
GC一开始运行,所有从根能到达的对象都会被标记,然后被放到栈里。GC只是发现了这样的对象,但还没有搜索完 它们,所以这些对象就成了灰色对象。
灰色对象被依次从栈中取出,其子对象也会被涂成灰色。当其所有子对象都被涂成灰色时,对象就会被涂成黑色。
当GC结束时已经不存在灰色对象,活动对象全部为黑色,垃圾则为白色。
增量式标记清除算法
分成三个阶段:
根查找阶段:能直接从GC根引用的对象涂为灰色
标记阶段:查找灰色对象,将其子对象涂为灰色,查找结束后将灰色对象涂为黑色
清除阶段:查找堆,将白色对象用空闲链表链接回收,黑色对象变为白色
根查找阶段
该阶段mutator线程会被中断。根据GC根查找直接引用的对象将其标记为灰色,加入标记栈中。该阶段结束后重新启动mutator线程。
标记阶段
与mutator线程交替执行。遍历标记栈中的灰色对象,访问其子对象后将对象标记位黑色。将标记为灰色的子对象加入标记栈,将标记 为黑色的对象冲标记栈中去除。由于mutator和标记线程交替执行,因此会出现GC根引用的变化,需要重新扫描GC根。
标记阶段存在的问题
图(a)是刚刚暂停标记阶段后的状态,A的所有子对象被搜索过被涂成黑色,B的子对象尚未被搜索被涂成黑色。所以接下来就要对B进行搜索了。在此我们继续 执行mutator。
图(b)是 mutator把A指向B的引用更新为从A指向C的状态,然后再删除从B指向C的引用,就成了图(c)。
mutator的这个修改导致原本被对象B(待标记)引用的对象C被对象A(已经标记结束)引用。会导致对象C漏标。
写屏障+增量更新
在对对象引用进行更新时拦截新的引用newObj。
如果新引用的对象newObj没有被标记,那么就将其标记后放入标记栈中。换而言之,就是如果newObj对象是白色,就把它涂成灰色。
清除阶段
同普通的标记-清除算法,使用空闲链表将垃圾对象回收。
分配
如果空闲区域尺寸不足则进行GC。从空闲链表分配一块空间,如果当前处于清除阶段且分配空间所在区域尚未清除,则将新分配空间设置为灰色。返回空间地址。
优点
缺点
引入了写入屏障,增加额外负担,影响mutator的吞吐量
汤浅太一的算法
也称为快照GC,它以GC开始时对象间的引用关系(snapshot)为基础来执行GC。在GC开始回收垃圾时,保留GC开始 时的活动对象和GC执行过程中新分配的对象。
标记阶段
进入标记阶段后不需要再搜索根,因为它遵循了“以GC开始时对象间的引用关系为基础执行GC”这个原则。
写入屏障+快照
当引用变更时,如果引用的旧对象oldObj为白色对象。
当GC进入标记阶段且oldObj未被标记,则将其标记为灰色并加入标记栈中。
分配