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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章