第一款真正意义上的并发垃圾回收器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] 举报,一经查实,本站将立刻删除。