CMS收集器

  • CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間爲目標的收集器。
  • 目前很大一部分的Java應用集中在互聯網站或者B/S系統的服務端上,這類應用尤爲重視服務的響應速度,但願系統停頓時間最短,以給用戶帶來較好的體驗。CMS收集器就很是符合這類應用需求。
  • 從名字(包含「Mark Sweep」)上就能夠看出,CMS收集器是基於「標記-清除」算法實現的,它的運做過程相對於前面幾種收集器來講更復雜一些,整個過程分爲4個步驟,包括:
    • 初始標記(CMS initial mark)
    • 併發標記(CMS concurrent mark)
    • 從新標記(CMS remark)
    • 併發清除(CMS concurrent sweep)
  • 其中,初始標記、從新標記這兩個步驟仍然須要「Stop The World」。
  • 初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快,併發標記階段就是進行GC Roots Tracing的過程,而從新標記階段是爲了修正併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但遠比並發標記的時間短。
  • 因爲整個過程當中耗時最長的併發標記和併發清除過程收集器線程均可以與用戶線程一塊兒工做,因此,從整體上來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發執行的。經過下圖能夠比較清除看見CMS收集器的運做步驟中併發和須要停頓的時間。
  • CMS是一款優秀的收集器,它的主要優勢在名字上已經體現出來了:併發收集、低停頓。可是CMS還遠達不到完美的程度,它有如下3個明顯的缺點:算法

    CMS收集器對CPU資源很是敏感。
  • 其實,面向併發設計的程序都對CU資源比較敏感。在併發階段,它雖然不會致使用戶線程停頓,可是會由於佔用了一部分線程(或者說CPU資源)而致使應用程序變慢,總吞吐量會下降。
  • CMS默認啓動的回收線程數是(CPU數量+3)/ 4,也就是當CPU在4個以上時,併發回收時垃圾收集線程很多於25%的CPU資源,而且隨着CPU數量的增長而降低。
  • 可是當CPU不足4個(譬如2個)時,CMS對用戶程序的影響就可能變得更大,若是原本CPU負載比較大,還分出一半的運算能力去執行收集器線程,就可能致使用戶程序的執行速度突然下降了50%,其實也讓人沒法接受。
  • 爲了應付這種狀況,虛擬機提供了一種稱爲「增量式併發收集器」的CMS收集器變種,所作的事情和單CPU年代PC機操做系統使用搶佔式來模擬多任務機制的思想同樣,就是在併發標記、清理的時候讓GC線程、用戶線程交替運行,儘可能減小GC線程的獨佔資源的時間,這樣整個垃圾收集的過程會更長,但對用戶程序的影響就會顯得少一些,也就是速度降低沒有那麼明顯。
  • 實踐證實,增量時的CMS收集器效果很通常,在目前版本中,i-CMS已經被聲明爲「deprecated」,即再也不提倡用戶使用。併發

CMS收集器沒法處理浮動垃圾,可能出現「Concurrent Mode Failure」失敗而致使另外一次Full GC的產生。
  • 因爲CMS併發清理階段用戶線程還在運行着,伴隨程序運行天然就還會有新的垃圾不斷產生,這一部分垃圾出如今標記過一部分垃圾就稱爲「浮動垃圾」。
  • 也是因爲垃圾收集階段用戶線程還須要運行,那也就須要預留有足夠的內存空間給用戶線程使用,所以CMS收集器不能像其餘收集器那樣等到老年代幾乎徹底被填滿了再進行收集,須要預留一部分空間提供併發收集時的程序運做使用。
  • 在JDK1.5的默認設置下,CMS收集器當老年代使用了68%的空間後就會被激活,這是一個偏保守的設置,若是在應用中老年代增加不是太快,能夠適當調高參數-XX:CMSInitiatingOccupancyFraction的值來提升觸發百分比,以便下降內存回收次數從而獲取更好的性能。
  • 在JDK1.6中,CMS收集器的啓動閾值已經提高至92%。要是CMS運行期間預留的內存沒法知足程序須要,就會出現一次「Concurrent Mode Failure」失敗,這時虛擬機將啓動後備預案:臨時啓動Serial Ol收集器來從新進行老年代的垃圾收集,這樣停頓時間就很長了。因此說參數-XX:CMSInitiatingOccupancyFraction設置得過高很容易致使大量「Concurrent Mode Failure」失敗,性能反而下降。
CMS是一款基於「標記-清除」算法實現的收集器,這意味着收集結束時會有大量空間碎片產生。
  • 空間碎片過多時,將會給大對象分配帶來很大麻煩,每每會出現老年代還有很大空間剩餘,可是沒法找到足夠大的連續空間來分配當前對象,不得不提早觸發一次Full GC。
  • 爲了解決這個問題,CMS收集器提供了一個-XX:+UseCMSCompactAtFullCollection開關參數(默認是開啓的),用於在CMS收集器頂不住要進行FullGC時開啓內存碎片的合併整理過程,內存整理的過程是沒法併發的,空間碎片問題沒有了,但停頓時間不得不變長。
  • 虛擬機設計者還提供了另一個參數-XX:CMSFullGCsBeforeCompaction,這個參數是用於設置執行多少次不壓縮的Full GC後,跟着來一次帶壓縮的(默認值爲0,表示每次進入Full GC時都進行碎片整理)。
相關文章
相關標籤/搜索