本文部分摘自《深入理解 Java 虛擬機第三版》
概述
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器,由于大部分 Java 應用主要集中在互聯網網站以及基于瀏覽器的 B/S 系統的服務端,這類應用通常會較為關注服務的回應速度,希望系統的停頓時間盡可能少,CMS 收集器就非常符合這類應用的需求
步驟
從名字可以知道,CMS 收集器是基于標記 - 清除演算法實作的,它的運作程序分為四個步驟:
-
初始標記(CMS initial mark)
僅僅只是標記一下 GC Roots 能直接關聯到的物件,速度很快,需要 Stop The World
-
并發標記(CMS concurrent mark)
就是從 GC Roots 的直接關聯物件開始遍歷整個物件圖的程序,耗時較長,但不需要停頓用戶執行緒,可與垃圾收集器執行緒一起并發執行
-
重新標記(CMS remark)
該階段是為了修正并發標記期間,因用戶程式運作而導致標記產生變動的那一部分物件的標記記錄,這個階段需要 Stop The World,而且停頓時間通常比初始階段稍長一些,但也遠比并發標記階段的時間短
-
并發清除(CMS concurrent sweep)
清理洗掉掉標記階段判斷已經死亡的物件,由于不需要移動存活物件,所有這個階段可以和用戶執行緒并發執行
由于整個程序中耗時最長的是并發標記和并發清除階段,而這兩個階段都可以和用戶執行緒并發執行,所以從總體上看,CMS 收集器記憶體回收程序是與用戶執行緒一起并發執行的

CMS 收集器的不足
CMS 收集器的主要優點就是:并發收集、低停頓,因此也稱 CMS 收集器為并發低停頓收集器,但 CMS 還遠未達到完美的程度,它至少有以下四個明顯的缺點:
-
對處理器資源非常敏感
在并發階段,CMS 雖然不會導致用戶執行緒停頓,但卻會因為占用了一部分執行緒(或者說是處理器的計算能力)而導致應用程式變慢,降低吞吐量,處理器核心數在四個或以上那還好,如果不足四個,CMS 會占用將近一半的運算能力去執行收集器執行緒,這將導致用戶程式的執行效率大幅降低
-
無法處理浮動垃圾
在 CMS 的并發標記和并發清理階段,由于用戶執行緒繼續運行,因此有可能會有新的垃圾物件產生,但這一部分垃圾物件是出現在標記結束之后,CMS 無法在當次收集中處理掉它們,只能留待下一次垃圾收集在清理,這一部分垃圾就稱為浮動垃圾
-
可能會出現并發失敗
同樣也是由于垃圾收集階段用戶執行緒還需持續執行,那就必須預留足夠的記憶體空間供用戶執行緒使用,因此 CMS 收集器不能像其他收集器那樣等老年代幾乎完全填滿再進行收集,而必須預留一部分空間供并發收集時的程式運作使用,這部分空間的大小可以通過 -XX:CMSInitiatingOccu-pancyFraction 引數來設定,如果 CMS 運行期間預留的記憶體無法滿足程式分配物件的需要,就會出現一次并發失敗,這時虛擬機不得不啟用預備方案:凍結用戶執行緒,臨時啟用 Serial Old 收集器來重新進行老年代的垃圾收集,導致 Stop The World
-
大量空間碎片的產生
CMS 是一款基于標記 - 清除演算法實作的收集器,這也意味著收集結束時會產生大量空間碎片,為了解決這個問題,CMS 收集器提供了一個 -XX:+UseCMS-CompactAtFullCollection 開關引數,用于在收集結束后做一次記憶體整理,以及 -XX:CMSFullGCsBefore-Compaction 引數,要求 CMS 收集器在執行若干次不整理空間的 Full GC 之后,下一次 Full GC 前先做一次碎片整理
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/240750.html
標籤:Java
上一篇:Java Web學習筆記(一)
下一篇:常用的學習網站和小工具
