什么是三色标记法

垃圾回收算法主要有有两种,追踪式垃圾回收算法引用计数法( Reference counting )。三色标记法属于追踪式垃圾回收算法的一种。

追踪式算法的核心思想是判断一个对象是否可触达,因为一旦对象不可触达就应该被 GC 回收了。那么如何得知一个对象是否可达呢?具体如下:

  1. 找出所有的全局变量和当前函数栈里的变量,标记为可达。
  2. 从已标记的数据开始,进一步标记它们可访问的变量,以此类推,也就是我们经常提到的传递闭包

标记法中有个算法叫 Mark-And-Sweep (标记清扫),该算法是严格按照追踪式算法的思路实现的。首先为所有对象标记为 0,如果发现对象是可达的就会置为 1,一步步下去就会呈现一个类似树状的结果。待标记的步骤完成后,会将未被标记的对象统一清理,再次把所有的标记位设置成 0 方便下次清理。

这个算法最大的问题是 GC 执行期间需要把整个程序完全暂停,不能异步进行 GC 操作。因为在不同阶段标记清扫法的标志位 0 和 1 有不同的含义,那么新增的对象无论标记为什么都有可能意外删除这个对象。对实时性要求高的系统来说,这种需要长时间挂起的标记清扫法是不可接受的。所以就需要一个算法来解决 GC 运行时程序长时间挂起的问题。

三色标记法就是为了解决这个问题而出现的。它将对象标记为黑、白、灰三种颜色,黑色对象为可达对象,应该保留,白色对象为不可达对象,应该被清除,灰色作为中间过度态。如下图:

三色标记法三色标记法

因为三色标记法多了一个白色的状态来存放不确定的对象,所以可以异步地执行。当然异步执行的代价是可能会造成一些遗漏,因为那些早先被标记为黑色的对象可能目前已经是不可达的了。所以三色标记法是一个 false negative(假阴性)的算法。

除了异步标记的优点,三色标记法掌握了更多当前内存的信息,因此可以更加精确地按需调度,而不用像标记清扫法那样只能定时执行。