微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JVM之CMS垃圾回收器

第一款真正意义上的并发垃圾回收器Concurrent Mark Sweep并发标记清除垃圾回收器

垃圾回收的主要流程为以下

1.初始标记:发生STW,初始标记阶段仅仅是标记一下GC roots能够直接引用的对象,就恢复用户线程的执行,因此暂停时间很短。

2.并发标记:并发标记就是从初始标记过的那些对象出发,遍历整个对象图的过程。

由于用户线程和标记线程一块执行,所以并发标记中存在一些问题:

  • 多标:原本是在对象整个引用链中的,在标记过后引用断开了,变成了垃圾对象,这种属于浮动垃圾,本次垃圾回收无法清理。
  • 漏标:CMS使用的是三色标记法(没了解过的同学需要去了解一下),使得原本应该标记为黑色的对象,被标记成了白色。
    原本标记为黑色的对象被标记为了白色必须同时满足下面两个条件
    (1) 赋值器插入了一条或多条从黑色对象到白色对象的引用。(因为黑色对象一般来说不会再进行遍历,所以白色对象的状态不会该表)
    (2)赋值器删除了所有从灰色对象到该白色对象的引用。(所有白色对象都是经由灰色对象遍历到从而变灰再变黑)

3.重新标记

重新标记要做的工作就是修复在并发标记中引用发生的修改,该部分也是STW的,不然如果引用一直修改的话,重新标记将会一直无法结束。

CMS采用的是 写屏蔽+ 增量更新完成漏标的问题

假设现在有黑色节点 A ,灰色节点B 白色节点C

A -->> B -->> C

在这里插入图片描述

此时引用发生改变了 A–>>B并且 A–>>C

在这里插入图片描述

漏标的代码如下

Obj var = B.fieldC;
B.fieldC = null;
A.fieldC = var;

写屏障+增量更新
写屏障+增量更新的思路就是破坏第一个条件:黑色节点插入了白色节点的引用。当黑色节点插入了白色节点的引用时,即A.fieldC = var;我们记录下当前黑色节点,在重新标记的阶段将该节点再次进行遍历。(实际上相当于插入白色结点之后将黑色节点变为灰色节点)

写屏障+SATB (Snapshot at the begin)

写屏障+原始快照的思路是破坏第二个条件:当灰色节点删除了对应白色节点的引用B.fieldC = null;,将该白色节点的引用加入到待遍历的集合中,即以一开始的对象图的来进行遍历。这样可能会产生多标的问题,下次进行垃圾回收再进行收集即可。

4.并发清除

并发清除阶段的问题:

1.黑色对象变为白色对象

当我们进行并发清除的时候,如果黑色对象所有指向它的引用都被清除了,那么他就变成了浮动垃圾,本次垃圾回收并不会对他进行清除。

2.白色对象变为黑色对象(不可能)

这种情况明显不可能,白色对象只能通过灰色对象可达,但是上述三个阶段完成之后,对象只剩下白色和黑色对象,所以无法将任何一个白色对象的引用重新接上黑色对象。

3.新对象会不会被误删除?

新对象创建肯定没有被标记为黑色,为什么新对象不会被删除呢?因为在垃圾回收阶段,新对象会被分配到空闲列表的指定区域,gc不会对这片区域进行回收。

5.CMS存在的问题

浮动垃圾,所以CMS不能到内存彻底不够用时才进行回收,需要提前进行回收以达到有内存缓冲的目的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐