CMS 收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。

CMS 收集器是基于标记-清除算法实现的,它的运作过程分为四个步骤:

  1. 初始标记(CMS initial mark):初始标记仅仅只是标记一下 GCRoots 能直接关联到的对象,速度很快;

  2. 并发标记(CMS concurrent mark):并发标记阶段就是从 GC Roots 的直接关联对象开始遍历整个对象图的过程,这个过程耗时较长但是不需要停顿用户线程,用户线程可以与垃圾收集线程一起并发运行;

  3. 重新标记(CMS remark):重新标记阶段则是为了修正并发标记期间,因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间通常会比初始标记阶段稍长一些,但也远比并发标记阶段的时间短;

  4. 并发清除(CMS concurrent sweep):清理删除掉标记阶段判断的已经死亡的对象,由于不需要移动存活对象,所以这个阶段也是可以与用户线程同时并发的。

其中初始标记、重新标记这两个步骤仍然需要 “Stop The World”。

CMS 是一款优秀的收集器,它最主要的优点是:并发收集、低停顿。同时,它拥有三个主要的缺点:

  • 首先,CMS 收集器对处理器资源非常敏感。在并发阶段,它虽然不会导致用户线程停顿,但却会因为占用了一部分线程(或者说处理器的计算能力)而导致应用程序变慢,降低总吞吐量。

  • 然后,由于 CMS 收集器无法处理“浮动垃圾”(Floating Garbage),有可能出现 “Concurrent Mode Failure” 失败进而导致另一次完全 “Stop The World” 的 Full GC 的产生。

  • 最后,CMS 是一款基于“标记-清除”算法实现的收集器,这意味着收集结束时会有大量空间碎片产生。空间碎片过多时,将会给大对象分配带来很大麻烦,往往会出现老年代还有很多剩余空间,但就是无法找到足够大的连续空间来分配当前对象,而不得不提前触发一次 Full GC 的情况。

浮动垃圾

在 CMS 的并发标记和并发清除阶段,用户线程是还在继续运行的,程序在运行自然就还会伴随有新的垃圾对象不断产生,但这一部分垃圾对象是出现在标记过程结束以后,CMS 无法在当次收集中处理掉它们,只好留待下一次垃圾收集时再清理掉。这一部分垃圾就称为“浮动垃圾”。

由于在垃圾收集阶段用户线程还需要持续运行,那就还需要预留足够的内存空间提供给用户线程使用,因此 CMS 收集器不能像其他收集器那样等待到老年代几乎完全被填满了再进行收集,必须预留一部分空间供并发收集时的程序运作使用。

最后更新于