君子以自强不息。
混合回收的两个阶段
- 并发标记,目的是识别老生代分区中的活跃对象,并计算分区中垃圾对象所占空间的多少,用于垃圾回收过程中判断是否回收分区。
- 垃圾回收,这个过程和新生代回收的步骤完全一致,重用了新生代回收的代码,最大的不同是在回收时不仅仅回收新生代分区,同时回收并发标记中识别到的垃圾多的老生代分区。
混合回收涉及新生代和老生代,老生代可能会花费更多的时间。所以这里引入了并发标记,这里的并发标记指的是标记工作线程可以和 Mutator 同时运行,当然并发标记引入了复杂度。
并发标记
并发标记存在一个问题:在标记对象的过程中,Mutator 可能正在改变对象引用关系图,从而造成漏标和错标。错标不会影响程序的正确性,只是造成所谓的浮动垃圾。但漏标则会导致可达对象被当做垃圾收集掉,从而影响程序的正确性。为了解决这个问题 G1 引入了三色标记法来区分对象的不同状态。
三色标记法
三色标记法顾名思义从逻辑上将对象分为三种颜色:
- 白色:还没有被收集器标记的对象。
- 灰色:自身已经被标记到,但其拥有的 field 字段引用到的其他对象还没有被处理。
- 黑色:自身已经被标记到,且对象本身所有的 field 引用到的对象也已经被标记。
什么情况会发生漏标
- Mutator 插入了一个从黑色对象到该白色对象的新引用,因为黑色对象已经被标记,如果不对黑色对象重新处理,那么白色对象将被漏标,造成错误。
- Mutator 删除了所有从灰色对象到该白色对象的直接或者间接引用,因为灰色对象正在标记,字段引用的对象还没有被标记,如果这个引用的白色对象被删除了(引用发生了变化),那么这个引用对象也有可能被漏标。
如何解决漏标问题
- 增量更新算法关注对象引用插入,把被更新的黑色或者白色对象标记成灰色。
- SATB 关注引用的删除,即在对象被赋值前,把老的被引用对象记录下来,然后根据这些对象为根重新标记一遍。