1、簡介
Concurrent Mark Sweep,是一種以獲取最短回收停頓時間爲目標的收集器,尤爲重視服務的響應速度。算法
CMS是老年代垃圾回收器,基於標記-清除算法實現。新生代默認使用ParNew收集器,基於複製算法安全
2、垃圾回收過程
分爲四個步驟進行垃圾回收:初始標記,併發標記,從新標記,併發清除。只有初始標記和從新標記須要停頓。併發
- 初始標記。只是標記一下GC Roots能直接關聯到的老年代對象,速度很快。這一階段會STW
- 併發標記。就是進行GC Roots的Tracing,處理器能夠與用戶線程一塊兒工做。
- 從新標記。爲了修正併發標記期間因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段也會觸發STW,停頓時間會比初始標記階段稍長,遠比並發時間短。
- 併發清除,處理器能夠與用戶線程一塊兒工做。
可達性分析方法性能
- 經過一系列的稱爲「GC Roots」的對象做爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲「引用鏈」,當一個對象到GC Roots沒有任何引用鏈相連時,說明這個對象是可回收的。
- Java語言中,可做爲GC Roots的對象包括如下幾種:虛擬機棧中引用的對象,方法區中類靜態屬性引用的對象,方法區中常量引用的對象,本地方法棧中引用的對象。
3、垃圾回收觸發時機
新生代垃圾回收觸發時機:當 eden 區內存沒法爲一個新對象分配內存時,就會觸發 Minor GCspa
老年代垃圾回收觸發時機:線程
一、若是沒有設置-XX:+UseCMSInitiatingOccupancyOnly,虛擬機會根據收集的數據決定是否觸發(建議線上環境帶上這個參數,否則會加大問題排查的難度)。
二、老年代使用率達到閾值
CMSInitiatingOccupancyFraction
,默認92%。
三、永久代的使用率達到閾值
CMSInitiatingPermOccupancyFraction
,默認92%,前提是開啓
CMSClassUnloadingEnabled
。
四、新生代的晉升擔保失敗。老年代沒有足夠的空間來容納所有的新生代對象或歷史平均晉升到老年代的對象,若是不夠的話,就提前進行一次老年代的回收,防止下次進行YGC的時候發生晉升失敗。
4、垃圾回收如何作到STW
JVM有個叫作「安全點」和「安全區域」的東西,在發生GC時,全部的線程都會執行到「安全點」停下來。
在須要GC的時候,JVM會設置一個標誌,當線程執行到安全點的時候會輪詢檢測這個標誌,若是發現須要GC,則線程會本身掛起,直到GC結束才恢復運行。code
可是對於一些沒有得到或沒法得到CPU時間的線程,就沒辦法等到它執行到安全點了,因此這個時候只要這個線程是在安全區域的,也能夠進行GC,安全區域是一段代碼段,在這段代碼段中對象的引用關係不會發生變化,因此這個時候進行GC也是安全的。對象
5、關於FullGC
- Full GC == Major GC指的是對老年代/永久代的stop the world的GC
- Full GC的次數 = 老年代GC時 stop the world的次數
- Full GC的時間 = 老年代GC時 stop the world的總時間
- CMS 不等於Full GC,咱們能夠看到CMS分爲多個階段,只有stop the world的階段被計算到了Full GC的次數和時間,而和業務線程併發的GC的次數和時間則不被認爲是Full GC。CMS主要能夠分爲initial mark(stop the world), concurrent mark, remark(stop the world), concurrent sweep幾個階段,其中initial mark和remark會stop the world。
6、CMS缺點
- 垃圾回收時會佔用一部分線程,致使系統變慢,總吞吐量會下降。
- 沒法處理浮動垃圾,須要預留足夠的內存空間給用戶線程使用,能夠經過 -XX:CMSInitiatingOccupancyFraction 參數控制觸發垃圾回收的閾值。
- 若是預留的內存沒法知足程序須要,就會出現「Concurrent Mode Failure」失敗,這時將啓動應急預案,啓用Serial Old 進行垃圾回收,停頓時間會變長。因此-XX:CMSInitiatingOccupancyFraction 參數的值設置的過高,會致使頻繁「Concurrent Mode Failure」失敗,性能反而下降。
- 標記-清理,容易產生內存碎片。-XX:+UseCMSCompactAtFullColletion 開啓碎片整理功能,默認開啓,-XX:CMSFullGCsBeforeCompaction,控制多少次不壓縮的FullGC以後來一次帶壓縮的
7、常見問題
一、promotion failed – concurrent mode failure
Minor GC後, Survivor空間容納不了剩餘對象,將要放入老年代,老年代有碎片或者不能容納這些對象,就產生了concurrent mode failure, 而後進行stop-the-world的Serial Old收集器。內存
解決辦法:-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 或者調大新生代或者Survivor空間ci
二、concurrent mode failure
CMS是和業務線程併發運行的,在執行CMS的過程當中有業務對象須要在老年代直接分配,例如大對象,可是老年代沒有足夠的空間來分配,因此致使concurrent mode failure, 而後須要進行stop-the-world的Serial Old收集器。
解決辦法:+XX:CMSInitiatingOccupancyFraction,調大老年帶的空間,+XX:CMSMaxAbortablePrecleanTime
三、碎片整理
-XX:+UseCMSCompactAtFullCollection 強制進行空間碎片整理
CMS 採用標記算法,會產生大量的空間碎片。以上參數就是強制執行一次空間碎片整理,可是空間碎片整理會引起STW。
-XX:+CMSFullGCsBeforeCompaction 配置通過幾回的FullGC進行空間碎片整理-XX:+CMSFullGCsBeforeCompaction=10 通過10次FGC後進行空間碎片整理,以下降STW次數