【JVM】落日黃昏後:CMS垃圾回收器

CMS(Concurrent Mark Sweep)應用場景

CMS是一種以獲取最短回收停頓時間爲目標的收集器。目前很大一部分的Java應用集中在互聯網網站或者基於瀏覽器的B/S系統的服務端上,這類應用一般都會較爲關注服務的響應速度,但願系統停頓時間儘量短,以給用戶帶來良好的交互體驗。CMS收集器就很是符合這類應用的需求。算法

CMS的運做過程

圖片
CMS收集器是基於標記-清除算法實現的,整個過程分爲四個步驟,包括:瀏覽器

  • 初始標記(initial mark)
    這個階段是STW的,但僅僅只是標記一下GCRoots能直接關聯到的對象,因此速度很快併發

  • 併發標記(concurrent mark)
    併發標記階段就是從GC Roots的直接關聯對象開始遍歷整個對象圖的過程,這個過程耗時較長可是不須要停頓用戶線程,能夠與垃圾收集線程一塊兒併發運行性能

  • 從新標記(remark)
    這個階段是STW的,爲了修正併發標記期間,因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但也遠比並發標記階段的時間短網站

  • 併發清除(concurrent sweep)
    清理刪除掉標記階段判斷的已經死亡的對象,因爲不須要移動存活對象,因此這個階段也是能夠與用戶線程同時併發的線程

CMS的優勢

  1. 併發收集垃圾
  2. 低延時

CMS的缺點

  1. CMS對處理器資源很是敏感。併發標記階段吞吐量較低,雖然不會致使用戶線程停頓,可是會致使應用程序變慢。由於有一部分CPU資源被分配給了垃圾收集線程4核CPU會分配25%的資源給垃圾回收線程,核數越多,分配給垃圾回收線程的資源比例佔總核數比例會降低。可是當CPU不足4核的時候,原本應用負載就已經很高了,若是再分一半的資源給垃圾收集線程就會致使程序的執行速度大幅度下降設計

  2. Con-current ModeFailure 觸發Full GC(STW)交由Serial Old收集器來收集。因爲在垃圾收集階段用戶線程還須要持續運行,那就還須要預留足夠內存空間提供給用戶線程使用,所以CMS收集器不能像其餘收集器那樣等待到老年代幾乎徹底被填滿了再進行收集,必須預留一部分空間供併發收集時的程序運做使用。在JDK5的默認設置下,CMS收集器當老年代使用了68%的空間後就會被激活,這是一個偏保守的設置,若是在實際應用中老年代增加並非太快,能夠適當調高參數-XX:CMSInitiatingOccu-pancyFraction的值來提升CMS的觸發百分比,下降內存回收頻率,獲取更好的性能。但若是這個值給的太高,好比90%,這又會更容易面臨另外一種風險:要是CMS運行期間預留的內存沒法知足程序分配新對象的須要,就會出現一次「併發失敗」(Concurrent Mode Failure),這時候虛擬機將不得不啓動後備預案:凍結用戶線程的執行,臨時啓用Serial Old收集器來從新進行老年代的垃圾收集,但這樣停頓時間就很長了。因此這個參數設置得過高將會很容易致使大量的併發失敗產生,性能反而下降,用戶應在生產環境中根據實際應用狀況來權衡設置對象

  3. 會產生內存空間碎片,分配大對象時空間不足提早觸發FGC。CMS是一款基於「標記-清除」算法實現的收集器,收集結束時會有大量空間碎片產生。空間碎片過多時,將會給大對象分配帶來很大麻煩,每每會出現老年代還有不少剩餘空間,但就是沒法找到足夠大的連續空間來分配當前對象,而不得不提早觸發一次Full GC。不過也能夠經過設置參數儘可能的避免這個狀況的發生,CMS收集器提供了一個-XX:+UseCMS-CompactAtFullCollection開關參數(默認是開啓的,此參數從JDK 9開始廢棄),用於在CMS收集器不得不進行Full GC時開啓內存碎片的合併整理過程,因爲這個內存整理必須移動存活對象,(在Shenandoah和ZGC出現前)是沒法併發的。這樣空間碎片問題是解決了,但停頓時間又會變長,所以虛擬機設計者們還提供了另一個參數-XX:CMSFullGCsBeforeCompaction(此參數從JDK 9開始廢棄),這個參數的做用是要求CMS收集器在執行過若干次(數量由參數值決定)不整理空間的Full GC以後,下一次進入Full GC前會先進行碎片整理(默認值爲0,表示每次進入Full GC時都進行碎片整理)blog

CMS特別須要注意的參數

  • -XX:CMSInitiatingOccu-pancyFraction:設置觸發老年代回收的閾值,避免發生Concurrent Mode Failure引起FGC
  • -XX:+UseCMS-CompactAtFullCollection:在CMS收集器不得不進行Full GC時開啓內存碎片的合併整理過程
  • -XX:CMSFullGCsBeforeCompaction

關於CMS的總結

雖然開創了併發回收垃圾的先河但因爲有Con-current ModeFailure會觸發FGC這個致命性的缺點,所以沒有任何版本的JDK採用CMS做爲默認的垃圾回收器,JDK9中CMS已經消失,但CMS併發回收垃圾的思想卻一直在延續圖片

相關文章
相關標籤/搜索