CMS低延遲垃圾收集器詳解

 

因爲熱愛所以堅持,因爲熱愛所以等待。熬過漫長無戲可演的日子,終於換來了人生的春天,共勉!!!

1.CMS概述

①. 在JDK1.5時期, HotSpot推出了一款在強交互應用中幾乎可認爲有劃時代意義的垃圾收集器: CMS (Concurrent 一Mark 一 Sweep)收集器,這款收集器是HotSpot虛擬機中第一款真正意義上的併發收集器,它第一次實現了讓垃圾收集線程與用戶線程同時工作

②. CMS收集器的關注點是儘可能縮短垃圾收集時用戶線程的停頓時間。停頓時間越短(低延遲)就越適合與用戶交互的程序,良好的響應速度能提升用戶體驗。

③. CMS的垃圾收集算法採用標記一清除算法,並且也會**" stop一the一world"**

④. 不幸的是,CMS 作爲老年代的收集器,卻無法與JDK 1.4.0 中已經存在的新生代收集器Parallel Scavenge配合工作,所以在JDK 1. 5中使用CMS來收集老年代的時候,新生代只能選擇ParNew或者Serial收集器中的一個

⑤. 在G1出現之前,CMS使用還是非常廣泛的。一直到今天,仍然有很多系統使用CMS GC

⑥. CMS收集器在JDK9中被廢棄,在JDK14中被移除

2.CMS過程(原理)

在這裏插入圖片描述

①. 初始標記(Initial一Mark)僅僅只是標記出和GCRoots能直接關聯到的對象,有STW現象、暫時時間非常短

②. 併發標記(Concurrent一Mark)階段:從GC Roots的直接關聯對象開始遍歷整個對象圖的過程,這個過程耗時較長但是不需要停頓用戶線程,可以與垃圾收集線程一起併發運行(併發標記階段有三色標記,下文有記錄)

③. 重新標記(Remark) 階段:由於在併發標記階段中,程序的工作線程會和垃圾收集
線程同時運行或者交叉運行,因此爲了修正併發標記期間,因用戶程序繼續運作而導
致標記產生變動的那一部分對象的標記記錄
,這個階段的停頓時間通常會比初始標記
階段稍長一些,但也遠比並發標記階段的時間短。

④. 併發清除:此階段清理刪除掉標記階段判斷的已經死亡的對象,釋放內存空間。由於不需要移動存活對象,所以這個階段也是可以與用戶線程同時併發的

⑤. 補充說明:

  • 由於最耗費時間的併發標記與併發清除階段都不需要暫停工作,所以整體的回收是低停****頓的。
  • 在CMS回收過程中,還應該確保應用程序用戶線程有足夠的內存可用。因此,CMS收集器不能像其他收集器那樣等到老年代幾乎完全被填滿了再進行收集,而是當堆內存使用率達到某一閾值時,便開始進行回收,以確保應用程序在CMS工作過程中依然有足夠的空間支持應用程序運行。要是CMS運行期間預留的內存無法滿足程序需要(生成垃圾的速度快過清理的速度),就會出現一次**“Concurrent Mode Failure”失敗,這時虛擬機將啓動後備預案:臨時啓用Serial 0ld**收集器來重新進行老年代的垃圾收集,這樣停頓時間就很長了。
  • CMS收集器的垃圾收集算法採用的是標記一清除算法,這意味着每次執行完內存回收後,由於被執行內存回收的無用對象所佔用的內存空間極有可能是不連續的一些內存塊,不可避免地將會產生一些內存碎片。 那麼CMS在爲新對象分配內存空間時,將無法使用指針碰撞(Bump the Pointer) 技術,而只能夠選擇空閒列表(Free List) 執行內存分配

⑥.既然Mark Sweep(標記清除)會造成內存碎片,那麼爲什麼不把算法換成Mark Compact(標記壓縮)呢?

答案其實很簡答,因爲當併發清除的時候,用Compact整理內存的話,會改變內存地址,原
來的用戶線程使用的內存會受影響
,要保證用戶線程能繼續執行,前提的它運行的資源不受影響。

3. CMS優缺點

①. 優點:併發收集、低延遲

②. CMS的弊端:

  • 會產生內存碎片,導致清理後無法分配大對象情況下,不得不提前觸發Full GC

  • **CMS收集器對CPU資源非常敏感。**在併發階段,它雖然不會導致用戶停頓,但是會因爲佔用了一部分線程而導致應用程序變 慢,總吞吐量會降低

  • CMS收集器無法處理浮動垃圾。可能出現"Concurrent Mode Failure" 失敗而導致另一次Full GC的產生。在併發標記階段由於程序的工作線程和垃圾收集線程是同時運行或者交叉運行的,那麼在併發標記階段如果產生新的垃圾對象,CMS將無法對這些垃圾對象進行標記,最終會導致這些新產生的垃圾對象沒有被及時回收,從而只能在下一次執行GC時釋放這些之前未被回收的內存空間

4. CMS參數設置

**①. -XX:+UseConcMarkSweepGC:**手動指定使用CMS收集器執行內存回收任務
(開啓該參數後會自動將一XX: +UseParNewGC打開。即: ParNew (Young區用) +CMS (0ld區用) +Serial 0ld的組合)

**②. -XX:CMSlnitiatingOccupanyFraction:**設置堆內存使用率的閾值,一旦達到該閾值,便開始進行回收

  • JDK5及以前版本的默認值爲68,即當老年代的空間使用率達到68%時,會執行一次CMS 回收。JDK6及以上版本默認值爲92%
  • 如果內存增長緩慢,則可以設置一個稍大的值,大的閾值可以有效降低CMS的觸發頻率,減少老年代回收的次數可以較爲明顯地改善應用程序性能。反之,如果應用程序內存使用率增長很快,則應該降低這個閾值,以避免頻繁觸發老年代串行收集器。因此通過該選項便可以有效降低Full GC的執行次數

**③. -XX:+UseCMSCompactAtFullCollection:**用於指定在執行完Full GC後對內存空間進行壓縮整理,以此避免內存碎片的產生。不過由於內存壓縮整理過程無法併發執行,所帶來的問題就是停頓時間變得更長了

**④. -XX:CMSFullGCsBeforeCompaction:**設置在執行多少次Full GC後對內存空間進行壓縮整理

**⑤. -XX:ParallelCMSThreads:**設置CMS的線程數量

  • CMS 默認啓動的線程數是(Parallel****GCThreads+3)/4
  • ParallelGCThreads 是年輕代並行收集器的線程數。當CPU 資源比較緊張時,受到CMS收集器線程的影響,應用程序的性能在垃圾回收階段可能會非常糟糕)

5.JDK後續版本CMS的變化

  • JDK9新特性: CMS 被標記爲Deprecate了

➢如果對JDK 9及以上版本的HotSpot虛擬機使用參數- XX:+UseConcMarkSweepGC來開啓CMS收集器的話,用戶會收到一個警告信息,提示CMS未來將會被廢棄。

  • JDK14新特性: 刪除CMS垃圾回收器

➢移除了CMS垃圾收集器,如果在JDK14中使用-XX: +UseConcMarkSweepGC的話,JVM不會報錯,只是給出一個warning信息,但是不會exit。JVM會自動回退以默認GC方式啓動JVM

參考視頻 : 尚硅谷JVM全套教程,百萬播放,全網巔峯(宋紅康詳解java虛擬機)
參考書籍 : 深入理解Java虛擬機

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章