Loading

GC算法-增量式垃圾回收

概述

增量式垃圾回收也并不是一个新的回收算法, 而是结合之前算法的一种新的思路.

之前说的各种垃圾回收, 都需要暂停程序, 执行GC, 这就导致在GC执行期间, 程序得不到执行. 因此出现了增量式垃圾回收, 它并不会等GC执行完, 才将控制权交回程序, 而是一步一步执行, 跑一点, 再跑一点, 逐步完成垃圾回收, 在程序运行中穿插进行. 极大地降低了GC的最大暂停时间.

实现

增量式垃圾回收只是提出了这样的一个概念, 并没有限定如何去实现. 想必也有不同的实现思路吧.

三色标记算法

此算法将对象做不同的标记

  • 白色: 未搜索过的对象
  • 灰色: 正在搜索的对象
  • 黑色: 搜索完的对象

这里的颜色只是一种虚构的概念, 就是在对象上打tag.

在GC开始执行时, 所有对象都是白色的, 然后将根集合的对象放到栈中, 并标记为灰色, 依次处理. 将对象从栈中取出, 递归搜索所有子对象, 并标记为灰色, 当子对象搜索完后, 就将对象标记为黑色. 这样, 当一个对象搜索完后, 该对象及其关联的所有子对象就都是黑色的了. 当标记阶段结束后, 所有活动对象都是黑色, 垃圾对象则是白色.

此算法就是通过这样, 逐步对对象进行标记.

三色标记应用于标记清除中

标记清除算法在标记阶段, 应用三色标记逐步标记, 每次搜索一定次数后, 就返回执行, 等待下次继续标记, 将标记分为小段穿插在程序中运行.

在清除阶段, 也可以设置一个次数, 每遍历一定数量的对象, 就返回等待下次继续.

三色标记不光可以应用于标记清除中, 也可以应用于其他标记算法中.

问题

你以为这就完了么? 天真, 想象一下这样的场景:

// 假设 c, d 是两个对象
$b->son = $d;
$b->son = $c;
// 在这个时候, 开始GC, 将d标记为白色, 将c标记为黑色. 返回
$b->son = $d;
// GC清除阶段, 将c对象保留, 将d对象回收

这样就出现问题了, 也就是说如果我已经对其进行过标记了, 但它在我标记之后进行了修改, 就会导致清除阶段的对象很可能不是当时的真实情况.

那么如何防止这种遗漏的标记呢? 简单粗暴一点, 每次更新指针的时候, 如果对象是白色的, 就将其涂成灰色, 放到待搜索的栈中, 之后重新对其进行标记. 这样就可以保证不会回收到引用的对象, 虽然可能会有一些遗漏对象没有回收, 但是 who care? 下一次再回收咯.

也有不同的写入屏障处理方法, 在更新对象时进行不同操作.

大概如此....

posted @ 2020-04-12 15:04  烟草的香味  阅读(871)  评论(0编辑  收藏  举报