2018-01-10 JVM篇 之 垃圾收集器

前言

本篇講一下各種GC之間的細微差異講的清楚的,希望通過本篇文章,讀者可以對GC的種類有更深刻的了解。
對于GC算法的可參數文章JVM篇之 GC算法

一、串行收集器-Serial

Serial收集器最古老的,最穩定的,歷經考驗,內部的BUG比較少的一個收集器,單個GC線程進行垃圾回收。

會作為CMS收集器降級處理時會使用此收集器。

JVM GC參數

增加JVM參數  -XX:+UseSerialGC 使用串行收集器,啟用此參數后
- 新生代、老年代使用串行回收
- 新生代使用復制算法
- 老年代使用標記-壓縮

回收過程如下圖:

串行收集器.png

通過上圖,可以看出在應用程序線程到達安全點后,會全部暫停,然后運行GC線程(單線程),GC線程線程執行完成之后,再開始執行應用線程。

缺點:因為是串行的,只使用一個線程進行回收,所以會產生較長的停頓時間,在多核的CPU上,是無法發揮CPU的性能

GC日志

Serial收集器GC日志 .png

當看GC日志有紅色加粗顯示的標識時,說明當前使用的是Serial收集器GC

二、并行收集器-ParNew

Serial收集器新生代并行版本,與Serial收集器相比只影響新生代的回收,此收集器需要多核cpu的支持,GC性能會更好。

JVM GC參數

增加JVM參數  -XX:+UseParNewGC ,啟用ParNew收集器,啟用之后
-新生代并行
-新生代使用復制算法
-老年代串行
-老年代使用標記-壓縮算法

由于新生代是并行回收,可以通過參數來調整并行回收的線程數量

  -XX:ParallelGCThreads 限制線程數量

ParNew收集器與Serial收集器主要區別在于,新生代的回收,前者是多線程回收,后者是單線程回收

回收過程如下圖:

ParNew收集器.png
通過上圖,可以看出在應用程序線程到達安全點后,會全部暫停,然后運行多個GC線程去做垃圾回收,GC線程線程執行完成之后,再開始執行應用線程。

GC日志

在GC日志中出現上圖中紅色加粗顯示的標識時,說明當前GC使用的是ParNew收集器,如下圖顯示
ParNew GC日志.png

三、Parallel收集器

  • Serial收集器在新生代和老年代的多線程版收集器
  • ParNew收集器,在老年代的并行版收集器

- 新生代復制算法
- 老年代 標記-壓縮
- 更加關注吞吐量

JVM GC參數

-XX:+UseParallelGC 
  - 新生代使用Parallel收集器 
  - 老年代串行
-XX:+UseParallelOldGC
  - 新生代使用Parallel收集器
  - 并行老年代

回收過程如下圖

圖片.png

GC日志

在GC日志中出現上圖中紅色加粗顯示的標識時,說明當前GC使用的是Parallel收集器,如下圖顯示!
Parallel GC日志.png

其它JVM參數

由于Parallel收集器比較關注吞吐量,所以還提供了一些配套的參數來控制GC的時間和占比

-XX:MaxGCPauseMills(停頓時間)
    設置GC的最大停頓時間,單位毫秒
    GC盡力保證回收時間不超過設定值
    作為一個GC的目標值
-XX:GCTimeRatio(可理解為吞吐量)
    GC所使用的CPU時間占用總時間的百分比
    在0-100的取值范圍
    默認99,即最大允許1%時間做GC

通常情況下,我們希望GC停頓時間短 ,同時又希望吞吐量高,但事實上這兩個參數是矛盾的。因為停頓時間和吞吐量不可能同時調優。在GC工作負載不變的情況下

  • 如果提高GC的頻率,因為頻率高了,所以每次GC要處理的垃圾就少了,GC速度自然速度就會加快,但是頻繁的GC會對系統的整體性能有損傷的,就會出現GC停頓時間短了,但是系統整體性能并不會很好。
  • 如果降低GC的頻率,自然而然每次要處理的垃圾就會增加,所以會導致每次GC的時間相對就會增加,但是對系統的整體性能是有所上升的。
對吞吐量的理解
  • cpu分到應用程序上的時間越多,吞吐量自然就會增加
  • cpu分到GC線程上的時間越多,處理應用線程就會越少。
    所以吞吐量,可以用應用線程占用CPU時間的長短來衡量。

在停頓時間和吞吐量兩者上,在GC工作負載不變的情況下,不可能兩者同時提高,個人認為除非優化GC算法,從根本上降低GC的工作負載。

所以在調試停頓時間 和吞吐量這兩個參數時,要根據實際情況來調整。

四、CMS收集器

CMS(Concurrent Mark Sweep) 并發標記清除,并發的意思是與用戶線程一起運行,從名字上可以理解,此算法是使用標記-清除算法,比較關注停頓時間 。

JVM GC參數

增加JVM參數  -XX:+UseConcMarkSweepGC,啟用CMS收集器,啟用之后
- 新生代使用ParNew收集器
- 新生代使用復制算法
- 老年代使用CMS收集器
- 老年代使用并發標記-清除

回收過程

因為CMS收集器要與用戶線程一起運行,所以它的算法和實現機制比較復雜,主要工作可以分為五步:

  • 初始標記
- 標識根節點直可達的對象
- 速度快
- 會產生STW
  • 并發標記(和用戶線程一起)
-  并發標記存活對象
- 占用時間相對較長
  • 重新標記
- 由于并發標記時,用戶線程依然運行因以在正式清理前,對有變化的對象,所以需要修正,對對象重新標記
- 會產生STW
  • 并發清除(和用戶線程一起)
-  基于標記結果,直接清理不可達的對象
  • 并發重置
- 為下一次CMS GC做準備
回收過程如下
cms回收過程.png

GC日志

 CMS-initial-mark  初始標記
 CMS-concurrent-mark  并發標記
 CMS-remark   重新標記
 CMS-concurrent-sweep  并發清除
 CMS-concurrent-reset  并發重置

具體的日志內容如下:
圖片.png
cms收集器的特點
  • 盡可能降低停頓
  • 會影響系統整體吞吐量和性能
    比如,在用戶線程運行過程中,分一半CPU去做GC,系統性能在GC階段,反應速度就下降一半
  • 清理不徹底
    因為在清理階段,用戶線程還在運行,會產生新的垃圾,無法清理
  • 與標記-壓縮相比會產生內存碎片
  • 并發階段會降低吞吐量

因為CMS收集器和用戶線程一起運行,所以不能在空間快滿時再清理,因為與用戶線程同時進入,如果在快滿的時候進行清理的話,很容易出兩用戶線程申請內存,出現concurrent mode failure的情況,所以JVM考慮到這點,提供相應的參數進行設置觸發GC的閾值

    -XX:CMSInitiatingOccupancyFraction設置觸發GC的閾值
    -XX:CMSInitiatingPermOccupancyFraction:當永久區占用率達到這一百分比時,啟動CMS回收
    -XX:CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少后觸發

即使設置了閾值也不能保證不會出現并發收集的錯誤 ,如果不幸內存預留空間不夠,就會引起concurrent mode failure,當發生這種情況之后,CMS收集器會降級到Serial收集器進行垃圾回收,這時候會暫停用戶線程,會產生一個長時間的停頓來回收垃圾。

下圖是發生concurrent mode failure時的GC日志
concurrent mode failure.png

有關碎片

因為CMS采用標記清除算法,所以會產生大量的內存碎片,所以JVM提供了兩個參數來對碎片進行整理

    -XX:+ UseCMSCompactAtFullCollection 
        Full GC后,進行一次整理
        整理過程是獨占的,會引起停頓時間變長(因為要移動大量的存活對象)
    -XX:+CMSFullGCsBeforeCompaction 
        設置進行幾次Full GC后,進行一次碎片整理
    -XX:ParallelCMSThreads 
       設定CMS的線程數量

五、各GC收集器對比

收集器 JVM參數 新生代 老年代
Serial -XX:+UseSerialGC 串行、復制算法 串行、標記壓縮算法
ParNew -XX:+UseParNewGC 并行、復制算法 串行、標記壓縮算法
Parallel -XX:+UseParallelGC -XX:+UseParallelOldGC 串行或并行、復制算法 串行或者并行、標記壓縮算法
CMS -XX:+UseConcMarkSweepGC 并行、復制算法 并發、標記清除算法

六、疑問

  • 為什么CMS不直接使用標記-壓縮算法呢?

作者:BK
http://www.lxweimin.com/u/a5230c4f0b7a
鑒于本人才疏學淺,不足之處還望斧正,也歡迎關注我,無特殊說明的都是自己一字一句碼出來的,尊重原創,如果轉載請說明出處!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,296評論 2 376