JVM - 并发标记之三色标记法和Pre-Write Barriers

概要

三色标记法是运用在GC并发标记过程中的算法,被扫描的对象们被分到三种集合里:

  • 白色集合:还没被标记 or 没有被标记到(这个就可以认为是垃圾了)
  • 灰色:标记到了,但是字段还没被标记完。
  • 黑色:标记完了。

所有标记完成后,会把白色的作为垃圾回收掉(因为不可达)。

步骤

  1. 创建:白、灰、黑 三个集合。
  2. 将所有对象放入白色集合中。
  3. 从GC Root开始遍历所有对象,把遍历到的对象从白色集合放入灰色集合(备注:这里放入灰色集合的都是GC Root的对象)。
  4. 遍历灰色集合,将灰色对象引用的对象(其实就是灰色对象的字段)从白色集合放入灰色集合,然后将分析过的灰色对象(所有字段都处理完毕的)放入黑色集合。
  5. 直到灰色中无任何对象。
  6. 通过写屏障(Pre-Write Barrier)检测对象有变化,重复以上操作(备注:因为 mark 和用户程序是并行的,所以在上一步执行的时候可能会有新的对象分配,写屏障是为了解决这个问题引入的)。
  7. 回收掉所有白色对象(垃圾)

关于Pre-Write Barrier

可以看到三色标记法有很多步骤,而这些步骤是和用户线程并发运行的,也就是说在标记过程中,用户还在创建新对象,或者抛弃老对象。

先讲创建新对象的情况:

  1. A对象已经被标记为黑色
  2. 用户线程:A.field = new X()

这种情况下,X是白色的,而且按照三色标记法的规则,黑色的A是不会再次被标记的。如果不能把X变成灰色,那么它就会被垃圾回收掉,这个是是存在问题的。

因此,在标记开始之后,需要在对象引用更新的地方添加一个Pre-Write Barrier,用来将X直接标记为灰色。

注意:Pre-Write Barrier和Post-Write Barrier作用的对象不同,前者是针对三色标记算法的缺陷,后者是针对Card Table。

参考资料

版权

评论