阅读 342

三色标记,增量更新与原始快照|8月更文挑战

三色标记,增量更新与原始快照|8月更文挑战

  前言: 前面主要讲解了常用的几种垃圾收集器,如有不了解的,点击 JVM垃圾回收器详解(上)-CMS收集器| 8月更文挑战# JVM垃圾回收器详解(下)-G1收集器| 8月更文挑战前往了解

三色标记

  之前说道的CMS与G1垃圾收集器都存在并发标记的过程,那么这两个垃圾收集器是如何标记的呢,答案就是三色标记法。在三色标记法中,Gcroots在可达性分析遍历对象过程中遇到的对象, 按照是否访问过这个条件标记成以下三种颜色:

  • 黑色: 表示该对象已经被垃圾收集器访问过,并且这个对象的所有的引用都一起扫描过了。黑色的对象代表它是安全存活的,如果有其他对象引用指向了黑色对象,无须重新扫描一遍。黑色对象不可能直接(不经过灰色对象) 指向某个白色对象。

  • 灰色: 表示该对象被垃圾收集访问过,但是这个对象的相关引用对象还没有被扫描过。

  • 白色:白色表示还没有被垃圾收集器访问过,比如刚开始进行可达性分析算法的时候,所有对象都是白色,在经过可达性分析算法后,被访问过的对象才会变成黑色或者白色,如果在分析结束后,对象还是白色,说明该对象为不可达对象。

image.png

那么既然是并发标记,就可能存在,比如D对象是开始存在,后面去掉或者开始没有,后面新增,那么就可能会发生多标或者漏标,如下图:

image.png

那么这种并发阶段会导致两种情况,多标与漏标:

  • 多标:产生浮动垃圾
  • 漏标:漏标会导致被引用的对象被当成垃圾删除,那么就会造成bug,对此的解决方案是增量更新原始快照

增量更新 Incremental Update

  增量更新就是黑色对象新增指向白色的引用关系的时候,就将回自个儿新增的引用记录下来,等并发标记扫描借宿后,再将这些记录过的引用关系中的黑色对象为根,再进行一次扫描。所以可以说当黑色对象新增了指向白色对象的引用之后,它就变成灰色对象了

原始快照 Snapshot At The Beginning

  原始快照(SATB)就是当有灰色对象需要删除指向白色的对象的引用关系的时候,将这个删除的引用记录下来,再并发结束之后,再将这些记录过的关系中以灰色对象为根,重新扫描一次,这样就能扫描到的白色对象,然后将这些对象标记成黑色(目的就是让这种对象在本轮gc清理中能存活下来,待下一轮gc的时候重新扫描,这个对象也有可能是浮动垃圾)

写屏障

  无论是增量更新对引用关系记录的插入与原始快照对引用关系的删除记录都是通过写屏障来实现的。写屏障其实跟spring中的AOP很类似,写屏障就是在赋值操作的前后加入处理。

  • 写屏障实现增量更新: 当某个对象的的成员变量的引用发生变化时,比如新增引用(a.b = b,我们可以利用写屏障,将a的成员变量引用对象b记录下来。

  • 写屏障实现SATB:当对象的成员变量的引用发生变化时,比如引用消失(a.b.c = null),我们可以利用写屏障,将b原来成员变量的引用对象c记录下来。

总结

对于CMS与G1两款收集器对并发标记时候的漏标主要处理方式如下:

  • CMS:增量更新+写屏障
  • G1: 写屏障+STAB

为什么G1用SATB?CMS用增量更新?

  G1讲究效率问题,SATB跟增量更新对比起来,STAB的效率会更高,但是也会产生更多的浮动垃圾,因为SATB不需要在重新标记阶段再次深度扫描被删除的引用对象,而且CMS与G1的分区不同,CMS是固定的老年代分区,而G1有很多的region,这就导致了很多对象位于不同的region,CMS只需要对一个区域进行深度扫描,如果G1选择增量更新,那么导致的代价会比较高,因此G1选择SATB,简单标记下,等到下次GC的时候再进行深度扫描。 Q.E.D.

文章分类
后端
文章标签