一般我们老年代的垃圾收集器都是使用的CMS(Concurrent Mark Sweep)。CMS使用的是标记-清理算法,工作流程大致是先标记需要回收的对象,然后回收垃圾,最后将存活的对象整理到一边,防止出现太多的内存碎片。有人说这不就是标记-整理算法吗,但是标记整理算法的步骤是先标记需要回收的对象,然后将存活的对象整理到一边,最后才将端边界之外的可回收对象清理。
因为在垃圾收集的时候,必然会产生“Stop the World”时间,让系统短暂不可用,所以CMS垃圾回收器采取的是垃圾回收线程和工作线程尽量同时执行的模式,减少系统的停顿。
CMS垃圾收集器分为4个阶段
- 初始标记
这个阶段需要STW(Stop the World),会停止所有的工作线程,然后标记所有GC Roots直接引用的对象,一般方法的局部变量和类的静态变量是GC Roots。这个阶段虽然会停止工作线程,但是标记GC Roots直接引用的对象速度非常块,所以影响很小。
- 并发标记
这个阶段工作线程和垃圾回收线程会一起工作,工作线程不停的创造新的对象,也有一些存活的对象失去引用,变成了垃圾对象,垃圾回收线程会将那些GC Roots可达的对象都标记出来。这个阶段是最耗时的阶段,因为是对老年代所有的对象进行GC Roots追踪,但是因为工作线程也在同时运行,所以不会让系统停顿。
2.5.并发预清理
这个阶段其实是为了给重新标记阶段减少工作量,此阶段标记从新生代晋升的对象、新分配到老年代的对象以及在并发阶段被修改了的对象。那如果老年代的对象引用到了新生代的GC Roots,如何来判断这个对象是否是存活的对象呢,那就需要扫描新生代来保证这个对象是否存活。全量扫描新生代和老年代的速度太慢,所以确定新生代对象是否存活需要进行一次Minor GC,这样就可以确认哪些新生代的对象存活,至于老年代,有一个CARD TABLE,CMS将老年代的空间分成大小为512bytes的块,CARD TABLE中的每个元素对应着一个块在并发标记阶段。老年代的对象引用发生了改变,这个对象所在的块就会被标记为Dirty Card,Minor GC通过扫描CARD TABLE,就可以识别到老年代的对象引用了新生代的对象,并将老年代的对象标记为可达,同时清除Dirty Card标记。
- 重新标记
因为在并发标记阶段中工作线程也是在同步工作的,所以会有一些存活的对象和一些失去引用的垃圾对象会被遗漏,因此重新标记阶段需要STW,来把并发标记中变动过的少数对象进行标记,所以这个阶段的速度也很快。
- 并发清理
这个阶段恢复了工作线程,同时把标记出来的垃圾对象进行回收。

CMS垃圾收集器的收集过程如图所示,CMS的优化点就是尽可能的减少STW时间,从而减少系统的卡顿,其中初始标记和重新标记阶段需要STW,但是一个是标记直接引用的对象,一个是对并发标记修改的少量对象进行标记,所以都不是很耗时,所以STW的时间很短,最耗时的并发标记和并发清理阶段,工作线程和垃圾处理线程都是同时工作的,不会很大程度上影响系统的运行。
CMS(Concurrent Mark Sweep)垃圾收集器采用标记-清理算法,通过四个阶段进行垃圾回收,尽量减少系统停顿。它在初始标记和重新标记阶段会暂停应用,其余阶段与应用程序并发执行。CMS通过并发预清理和并发清理阶段高效处理垃圾,以降低对系统性能的影响。
174万+

被折叠的 条评论
为什么被折叠?



