GC算法之CMS算法

CMS算法

CMS算法是JVM中老年代常用的垃圾回收算法,全称是Concurrent Mark Sweep算法,即并发标记-清除算法。算法的执行步骤如下图所示,共有六个步骤。

CMS-Steps

3.1 初始标记(Initial Mark):

CMS算法中两个会触发Stop the World事件中的一个,这个阶段会标记所有与GC Roots直接相关联的对象,以及被存活的青年代对象所直接引用的对象。

initial-mark

3.2 并发标记(Concurrent Mark):

并发标记,顾名思义,它是并发的执行标记任务的,这也就意味着GC在运行的过程中用户的应用线程并不会停止工作。该阶段GC收集器会从第一步“初始标记”中所标记出来的对象开始逐步遍历这些对象(与GCRoot直接相连或与存活的青年代对象直接相关联的对象)的所引用的对象,并将这些被引用的对象加上标记。
需要注意的是,这一步中,会漏掉一下老年代的存活对象,这是因为在并发的过程中,用户应用线程可能会对老年代的对象产生引用上的改变。某一些被改变的标记可能会被遗漏。

concurrent-mark

3.3 并发预清理(Concurrent Preclean):

并发预清理是Java1.5被加入进来的。主要目的是减少重标记(Remark)步骤Stop-the-World的时间。这一步同样也是并发的,不会停止用户应用线程。在前面的并发标记中,一些引用被改变了。当某一块块(Card)中的对象引用发生改变时,JVM会标记这个空间为“脏块”(Dirty Card)。

concurrent-preclean1

在预清理阶段,JVM根据之前记录的这些“脏对象”重新标记了他们新的可达对象。这一步结束后空间重新进入clean状态。另外,一些必要的最终重标记之前的准备步骤也会在这一步做好。

concurrent-preclean2

预清理步骤将会不断重复一直到Eden区的占用量达到某个指定的阈值。设定这个阈值作为结束条件的原因主要是为了防止YoungGC产生的Stop-the-World和下一阶段的Remark同时产生,导致系统产生一个更长的停滞。设定了这个阈值之后基本可以保证Remark阶段可以在两次YoungGC之间进行。

3.4 重标记(Remark):

这是CMS算法中第二个会触发Stop-the-World事件的步骤,由于前一步是一个并发的步骤,预清理的速度可能会赶不上用户应用对对象改变的速度,所以需要一个Stop-the-World的暂停来完整的标记所有对象结束整个标记阶段。
通常CMS会在年轻代为空时来运行重标记阶段,以此避免一个接一个的Stop-the-World阶段。

3.5 并发清理(Concurrent Sweep):

这一阶段程序并发地工作,目的是移除所有不用的对象,并且重新声明内存空间的归属等候将来使用。

concurrent-sweep

3.6 并发清理(Concurrent Reset):

并发地重置所有算法需要的内部数据结构,为下一次GC做准备。

3.7 CMS算法注意事项:

3.7.1 Concurrent Mode Failures

当CMS算法在并发的过程中堆空间无法满足用户程序对新空间的需求时,Stop-the-World的Full GC就会被触发,这就是Concurrent Mode Failures,这通常会造成一个长时间停顿。这种情况通常是因为老年代没有足够的空间供青年代对象promote。(包括没有足够的连续空间)

3.7.2 CMS相关JVM参数

  • -XX:+UseConcMarkSweepGC:激活CMS收集器,默认情况下使用ParNew + CMS + Serial Old的收集器组合进行内存回收,Serial Old作为CMS出现“Concurrent Mode Failure”失败后的后备收集器使用。
  • -XX:CMSInitiatingOccupancyFraction={x}:在老年代的空间被占用{x}%时,调用CMS算法对老年代进行垃圾回收。
  • -XX:CMSFullGCsBeforeCompaction={x}:在进行了{x}次CMS算法之后,对老年代进行一次compaction
  • -XX:+CMSPermGenSweepingEnabled & -XX:+CMSClassUnloadingEnabled:让CMS默认遍历永久代(Perm区)
  • -XX:ParallelCMSThreads={x}:设置CMS算法中并行线程的数量为{x}。(默认启动(CPU数量+3) / 4个线程。)
  • -XX:+ExplicitGCInvokesConcurrent:用户程序中可能出现利用System.gc()触发系统Full GC(将会stop-the-world),利用这个参数可以指定System.gc()直接调用CMS算法做GC。
  • -XX:+DisableExplicitGC:该参数直接让JVM忽略用户程序中的System.gc()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章