深入理解java虚拟机-三色标记

三色标记

本文不是为了介绍三色标记,而是为了说明三色标记的bug,以及CMS垃圾收集器为什么要进行重新标记。

三色标记的问题

浮动垃圾

三色标记其实就是并发标记(所有的并发垃圾收集器都是基于三色标记实现的)。所谓并发是垃圾回收线程和用户线程同时进行,所以就可能出现,本来是被标记成黑色的对象,随着用户线程的进行被修改成了白色,导致存在一部分垃圾无法被回收(等下次gc回收)。浮动垃圾并不是cms特有的,G1和Shenandosh等并发垃圾收集器也存在,因为都是基于三色标记实现的并发。

浮动垃圾只是少清除一些垃圾,对业务线程并没有影响。

漏标

所谓漏标,就是本来是黑色的对象,由于被遗漏,当成白色对象给清除了,因此漏标问题远比浮动垃圾严重的多。
三色标记中,黑色的对象不会被再次扫描(所有的引用对象都被扫描过才会被标记成黑色),但可能会存在下面的场景

黑色对象A重新引用了白色对象B,且此时B对象仅被A引用。由于黑色对象不会被再次扫描,故白色对象B永远不会被扫描成黑色,最终会被当成垃圾清除掉。

白色对象的处境有且只有两种情况:

  1. 这个对象当前没有被引用
  2. 这个对象有被灰色对象引用,只是还未扫描到

可见白色对象B只能是处境2的情况,因为如果是第1种情况,那么A是同样也无法引用对象B的,因为根本找不到。所以就是黑色对象A引用了被其他灰色对象引用的B对象,而其他灰色对象断开了引用,当前仅有A引用了B,B对象就会被漏标。
所以,漏标出现的必须要同时满足两个条件

  1. 有黑色对象(A)重新引用了白色对象(B)
  2. 引用或者间接引用该白色对象的灰色对象全部都断开了引用。(因为只要有一个灰色对象任仍然引用了B,B就会被重新扫描成黑色)。

所以,无论破坏任意一个条件都会解决三色标记的漏标问题

解决漏标

增量更新(破坏第一个条件)

其实很简单。即,当黑色对象A重新引用了白色对象B,那就把对象A重新置为灰色。cms垃圾收集器就是这么做的。

原始快照(破坏第二个条件)

不考虑断开的引用。即原来是C-B , 如果C和B之前的引用断开了,仍然按照C-B进行扫描,即扫描的是最初的快照(只要断开,就把B对象引用的快照拿来扫描)。G1和Shenandosh 采用的这个解决方案

CMS的bug

严谨点说不是cms的bug,是增量更新这个算法的bug。

对象A引用了两个对象B和C 即A-B,A-C
标记线程1开始扫描A对象,扫描了B,尚未扫描C
于此同时用户线程2重新将A引用了白色对象D,根据增量更新的算法,触发标记线程2将A标记成灰色,就在此时,标记线程1完成了A-C的扫描,用于A-B和A-C均已完成了扫描,于是将A对象标记成黑色(线程1并不知道A新引用了D),线程2执行的增量更新效果失效,D最终不会被扫描到,被当成垃圾回收掉。
这也是为什么cms会有重新标记的过程

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值