什么是三色标记

什么是三色标记

JVM 中的垃圾回收是基于 标记-复制、标记-清除和标记-整理三种模式的,那么其中最重要的其实是如何标记,像Serial、Parallel这类的回收器,无论是单线程标记和多线程标记,其本质采用的是暂停用户线程进行全面标记的算法,这种算法的好处就是标记的很干净,而且实现简单,缺点就是标记时间相对很长,导致STW的时间很长。
那么后来就有了并发标记,适用于CMS和G1,并发标记的意思就是可以在不暂停用户线程的情况下对其进行标记,那么实现这种并发标记的算法就是三色标记法,三色标记法最大的特点就是可以异步执行,从而可以以中断时间极少的代价或者完全没有中断来进行整个GC。

三色为那三色?

  • 白色:尚未被GC访问过的对象,如果全部标记已完成依旧为白色的,称为不可达对象,既垃圾对象。
  • 黑色:本对象已经被GC访问过,且本对象的子引用对象也已经被访问过了。
  • 灰色:本对象已访问过,但是本对象的子引用对象还没有被访问过,全部访问完会变成黑色,属于中间态。

两个问题

1. 多标-浮动垃圾

一个本应该是垃圾的对象被视为了非垃圾,它的影响并不会很大,因为哪怕此次不会被回收下一次也会被回收

2. 漏标-读写屏障

一个本应该不是垃圾的对象被视为了垃圾,如果误清理了正在被使用的对象,那肯定会出现问题。那么如何解决这个问题呢?
  出现这个问题的主要原因是,一个对象从被B引用,变更为了被A引用。那么对于A来说就是多了一个直接引用,对于B来说就是少了一个直接引用。我们可以从这两个方面入手来解决这个问题,对应了也有两个方案,分别是增量更新(Incremental Update) 和原始快照(SATB,Snapshot At The Beginning)

在这讲述解决方案之前,要描述两个名词:读屏障写屏障。注意,这里的屏障和并发编程中的屏障是两码事儿。这里的屏障很简单,可以理解成就是在读写操作前后插入一段代码,用于记录一些信息、保存某些数据等,概念类似于AOP。

2.1 增量更新

 增量更新是有重新标记的过程的,当黑色对象新增一个白色对象的引用时,就通过写屏障将这个引用关系记录下来。然后在重新标记阶段,再以这些引用关系中的黑色对象为根,再扫描一次,以此保证不会漏标。

        要实现也很简单,在重新标记阶段直接把A对象(和其它有相同情况发生的对象)变为灰色,放入队列中,再来一次枚举过程。要注意,在重新标记阶段如果用户线程还是继续执行,那么这个GC永远可能也做不完了,所以重新标记需要STW,但是这个时间消耗不会太夸张。如果实在重新标记阶段耗时过长,那么可以尝试在重新标记之前做一次Minor GC,这个在CMS垃圾收集器中有介绍。   

2.2 原始快照

        原始快照是站在减少引用的对象(也就是例子中的B对象)的角度来解决问题。所谓原始快照,就是在赋值操作之前添加了写屏障,在进行操作之前会记录对象引用,记录下来的这个对象就可以称为原始快照。在记录下来之后会直接将它变为黑色,标为不需要处理,在实际清理的时候如果有对象引用它则正常,如果没有则为浮动垃圾,在下一次回收时会清除掉,但是此方案会产生较多的浮动垃圾。

G1使用的是原始快照,CMS使用的是增量更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

余生大大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值