G1 混合回收

君子以自强不息。

混合回收的两个阶段

  • 并发标记,目的是识别老生代分区中的活跃对象,并计算分区中垃圾对象所占空间的多少,用于垃圾回收过程中判断是否回收分区。
  • 垃圾回收,这个过程和新生代回收的步骤完全一致,重用了新生代回收的代码,最大的不同是在回收时不仅仅回收新生代分区,同时回收并发标记中识别到的垃圾多的老生代分区。

混合回收涉及新生代和老生代,老生代可能会花费更多的时间。所以这里引入了并发标记,这里的并发标记指的是标记工作线程可以和 Mutator 同时运行,当然并发标记引入了复杂度。

并发标记

并发标记存在一个问题:在标记对象的过程中,Mutator 可能正在改变对象引用关系图,从而造成漏标和错标。错标不会影响程序的正确性,只是造成所谓的浮动垃圾。但漏标则会导致可达对象被当做垃圾收集掉,从而影响程序的正确性。为了解决这个问题 G1 引入了三色标记法来区分对象的不同状态。

三色标记法

三色标记法顾名思义从逻辑上将对象分为三种颜色:

  • 白色:还没有被收集器标记的对象。
  • 灰色:自身已经被标记到,但其拥有的 field 字段引用到的其他对象还没有被处理。
  • 黑色:自身已经被标记到,且对象本身所有的 field 引用到的对象也已经被标记。

什么情况会发生漏标

  • Mutator 插入了一个从黑色对象到该白色对象的新引用,因为黑色对象已经被标记,如果不对黑色对象重新处理,那么白色对象将被漏标,造成错误。
  • Mutator 删除了所有从灰色对象到该白色对象的直接或者间接引用,因为灰色对象正在标记,字段引用的对象还没有被标记,如果这个引用的白色对象被删除了(引用发生了变化),那么这个引用对象也有可能被漏标。

如何解决漏标问题

  • 增量更新算法关注对象引用插入,把被更新的黑色或者白色对象标记成灰色。
  • SATB 关注引用的删除,即在对象被赋值前,把老的被引用对象记录下来,然后根据这些对象为根重新标记一遍。