G1垃圾收集器之SATB

作者: 美团Java | 来源:发表于2017-10-09 12:08 被阅读1967次

    简书 占小狼
    转载请注明原创出处,谢谢!

    openjdk下载 传送门

    对象漏标

    垃圾回收的并发标记阶段,gc线程和应用线程是并发执行的,所以一个对象被标记之后,应用线程可能篡改对象的引用关系,从而造成对象的漏标、误标,其实误标没什么关系,顶多造成浮动垃圾,在下次gc还是可以回收的,但是漏标的后果是致命的,把本应该存活的对象给回收了,从而影响的程序的正确性。

    为了解决在并发标记过程中,存活对象漏标的情况,GC HandBook把对象分成三种颜色:

    1. 黑色:自身以及可达对象都已经被标记
    2. 灰色:自身被标记,可达对象还未标记
    3. 白色:还未被标记

    所以,漏标的情况只会发生在白色对象中,且满足以下任意一个条件:

    1. 并发标记时,应用线程给一个黑色对象的引用类型字段赋值了该白色对象
    2. 并发标记时,应用线程删除所有灰色对象到该白色对象的引用

    对于第一种情况,利用post-write barrier,记录所有新增的引用关系,然后根据这些引用关系为根重新扫描一遍

    对于第二种情况,利用pre-write barrier,将所有即将被删除的引用关系的旧引用记录下来,最后以这些旧引用为根重新扫描一遍

    SATB

    SATB全称snapshot-at-the-beginning,由Taiichi Yuasa为增量式标记清除垃圾收集器开发的一个算法,主要应用于垃圾收集的并发标记阶段,解决了CMS垃圾收集器重新标记阶段长时间STW的潜在风险。

    Region包含了5个指针,分别是bottom、previous TAMS、next TAMS、top和end,

    其中previous TAMS、next TAMS是前后两次发生并发标记时的位置,全称top-at-mark-start
    1、假设第n轮并发标记开始,将该Region当前的top指针赋值给next TAMS,在并发标记标记期间,分配的对象都在[next TAMS, top]之间,SATB能够确保这部分的对象都会被标记,默认都是存活的
    2、当并发标记结束时,将next TAMS所在的地址赋值给previous TAMS,SATB给 [bottom, previous TAMS] 之间的对象创建一个快照Bitmap,所有垃圾对象能通过快照被识别出来
    3、第n+1轮并发标记开始,过程和第n轮一样

    SATB保证了在并发标记过程中新分配对象不会漏标

    但如果在TAMS之前有一个白色对象W,被一个灰色对象G引用,在并发标记扫描到这个字段之前被赋值为null,切断了对象W和对象G之间的引用关系,对象W就有可能漏标,这就是白色对象被漏标的第二种情况?

    G1中如何解决?

    在引用关系被修改之前,插入一层 pre-write barrier

    pre-write barrier最终执行逻辑:

    通过G1SATBCardTableModRefBS::enqueue(oop pre_val)把原引用保存到satb mark queue中,和RSet的实现类似,每个应用线程都自带一个satb mark queue.

    在下一次的并发标记阶段,会依次处理satb mark queue中的对象,确保这部分对象在本轮GC是存活的。

    相关文章

      网友评论

        本文标题:G1垃圾收集器之SATB

        本文链接:https://www.haomeiwen.com/subject/ffbyyxtx.html