[翻译]G1垃圾收集器(四) 之 回顾GC以及CMS

回顾分代GC和CMS
并发标记扫描收集器(CMS),也被称作低暂停并发收集器。它是回收老年代。它试图利用和应用线程并发的收集尽可能多的垃圾,以减少因为垃圾收集导致的停顿。通常这种低延迟并发收集器不会对活动的对象进行压缩处理,也就是说它只做一个不对对象进行移动的垃圾回收,那么配分一个更大的内存的时候,碎片就会成为一个问题。

注意:CMS收集器在年轻代中使用和parallel 收集器相同的算法。

CMS收集阶段

CMS收集器在堆的老年代的回收上有以下几个阶段:

阶段 描述
初始化标记
(stop-the-world事件)
标记老年代中依然存活的对象,包括那些从年轻代晋升来的,这个过程通常比较短暂(译者注:存活我理解为被程序引用,不可回收的对象)
并发标记 和应用程序并发执行的,扫描整个老年代,是从那些标记的对象,或者间接标记的对象开始扫描。第2、3、5个阶段是并发执行的,在这个过程中,在CMS的代中新分配的对象(包括晋升的对象)会被立即标记为存活状态。
重新标记
(stop-the-world事件)
该阶段发现那些被并发标记错过的对象,因为并发标记是和应用程序并发执行的,在标记线程完成对某个对象的跟踪那刻,应用程序可能对对象进行了更新。
并发清理 收集那些在标记阶段没有标记的对象,消亡对象所占的空间会被添加到释放列表里用于重新分配,对死亡对象的聚集工作就发生在这个点。注意:存活的对象不会被移动。
并发重置 做一些数据结构的清理工作,为下一次收集做准备

回顾垃圾收集的步骤

接下来,让我们回顾一下CMS GC的操作步骤:

1、CMS GC的堆结构

整个堆被分成三个部分

CMS GC堆结构

年轻代被分割成一个Eden和和两个survivor区域,老年代是延续空间,对象的收集就在这片区域,没有压缩操作直到一个full GC发生。(译者注:读到这里,我们应该很清楚压缩的意思就是说不仅仅对垃圾对象进行收集,还对存活的对象进行腾挪,聚集在一起,腾出更多的空间,不要让对象散落在不同的空间,这就是内存碎片,内存碎片导致无法分配一块连续的大内存)

2、在CMS中,年轻代的GC是怎么工作的?

年轻代被标记为绿色,老年代为蓝色,你的JAVA程序在运行一段时间后,可能会像下面这个样子.对象分散的分布在老年代中:

CMS中的对象

使用CMS,老年代是对象消亡的地方,它们不会被移动,也不会被压缩,除非遇到一个Full GC.

3、年轻代的收集

存活的对象从 Eden 区域或者一个 survivor区域,移动到另外一个survivor区域,一些老的对象如果达到了晋升阈值,就会被提升到老年代中。CMS GC年轻代的晋升过程

4、年轻代GC之后

年轻代的收集之后,Eden区域和其中一个survivor区域会被清理

CMS 年轻代

新晋升的对象是深蓝色区域,绿色区域年轻代中存活下来,还没有晋升到老年代的对象。

5、CMS中老年代的收集

两次stop_the_world的时间是初始化标记和重新标记阶段,当老年代达到一定的占有率,CMS才开始登场了。

CMS 老年代

(1)初始化标记是对存活的对象进行标记,只有短暂的停顿(2) 并发标记阶段,是和应用程序一起执行的,也害死标记存活的对象。最终在第(3)阶段去标记那些上一阶段(2)遗漏的对象。

6、老年代的收集-并发清理

在上一阶段没有被标记的对象会在这里消亡,这里没有压缩。

CMS 老年代的收集

注意:未标记的对象就等于要消亡的对象(死亡对象)。

7、老年代的收集-清理过后

经过第(4)清理阶段之后,你会发现很多内存被释放了,你也会发现这里仍然没有压缩

CMS 并发清理之后

最终,CMS收集器会经过第(5)重置阶段,等待下一次满足GC条件(译者注:就是上文说到的,老年代达到了一定的占有率)。

留言

提示:你的email不会被公布,欢迎留言^_^

*

验证码 *