JVM Throughput和CMS垃圾回收器 原

垃圾收集器

Throughtput 垃圾收集器

簡介

Throughtput收集器是一款關注吞吐量的收集器。這個收集器也是唯一一個實現了UseAdaptiveSizePolicy策略的垃圾收集器。允許用戶通過指定最大的暫停時間和垃圾收集器所佔用的時間百分比,然後動態調整JVM的參數來達到配置的目標。

垃圾收集器

上圖是一個經典的垃圾收集器的圖,圖中有顏色的就是 throughput垃圾回收器 ,各個線代表的是各個垃圾回收器之間哪兩個可以配合使用。

從上圖可以看出 Parralel Scanvenge垃圾回收器不能和CMS配合使用。

ParallelScavenge收集器

ParallelScavenge收集器是新生代收集器,使用的是Scavenge GC。是一個並行收集器。在copping階段可以多個線程一起執行,在多線程的場景下可一儘量的提高Minor GC的效率。目的是可以達到一個可控的吞吐量。

吞吐量 = 運行用戶代碼的時間/(運行用戶代碼時間+垃圾收集時間)

虛擬機運行總時間100分鐘,其中垃圾收集器運行了1分鐘,則吞吐量就是99%

ParallelScavenge收集器的來歷爲,在HotSpot VM開發的時候都是在分代式框架下開發,並且希望第三方開發者也能在這個框架下開發自定義的收集器,這樣就能和其他收集器配合使用。但是有個開發者不願意使用這個框架,並且憑藉自己的能力開發了並行收集器,這時候JVM中的並行收集器是不存在的。經過測試,這個收集器的性能還是非常不錯的,於是就被放入到了HotSopt中成爲了ParallelScavenge收集器。這就是爲什麼這個收集器不能和CMS配合使用,因爲它就不是在分代式框架下開發的。

 

ParallelScavenge是在jdk1.7之前的默認垃圾回收器。使用ParallelScavence收集器需要需要關注以下兩個參數:

  1. MaxGCPauseMills

這個參數控制GC最大的停頓時間。設置以後通過動態調整新生代的大小來達到暫停時間是可以控制的。但是這個值不是越小越好。因爲這個如果這個值設置的比較小,那必定會導致新生代的比較小,新生代空間比較小的話,會導致更加頻繁的minor GC,這樣總間隔時間就會變大。

  1. GCTimeRatio

收集器運行時間所佔時間的比率,介於0到100的整數。

通過調整這兩個參數的大小能起到動態調整吞吐量和暫停時間的目的,這樣用戶不用關心新老年代應該各自設置多大,只需要設置好這兩個值,剩下的交給虛擬機動態調整。

Parallel Old

       Parallel Old是ParallelScavenge的老年代版本,之前如果新生代使用ParallelScavenge,老年代只能使用Serial Old,爲了彌補這個缺失,所以在jdk 1.6的時候開發了Parallel Old 老年代並行垃圾回收器,配合ParallelScavenge使用。此時兩者雙劍合璧,才更能顯現出來Throughtput的強悍之處

Serial Old收集器

       單線程老年代收集器,主要用在client模式下,不過也作爲CMS垃圾收集器併發模式失效以後備用收集器。

Throughtput收集器配置

Throughtput收集器通過第一節的圖中可以看出有兩種配置

  1. ParallelScavenge+Parallel Old
-XX:+UseParallelGC 

或者

 -XX:+UseParallelOldGC

,這兩個配置任選一個,就會選中ParallelScavenge+Parallel Old組合作爲收集器。

打印的GC日誌如下

 [Full GC (System.gc()) [PSYoungGen: 992K->0K(29696K)] [ParOldGen: 8K->761K(68608K)] 1000K->761K(98304K), [Metaspace: 3152K->3152K(1056768K)], 0.0060131 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
  1. ParallelScavenge+Serial Old

如果非得強制使用單線程老年代收集器(Serial Old)可以如下配置:

-XX:+UseParallelGC -XX:-UserParallelOldGC

發生GC時,打印的日誌如下

[Full GC (System.gc()) [PSYoungGen: 928K->0K(29696K)] [PSOldGen: 8K->767K(68608K)] 936K->767K(98304K), [Metaspace: 3167K->3167K(1056768K)], 0.0023446 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

ParallelScavenge和ParNew

在收集器的圖中,我們看到還有一個ParNew的新生代收集器,由於CMS收集器不能配合ParallelScavenge使用,所以只剩下一個單線程的Serial收集器,爲了能夠有所匹配,所以出來了並行的新生代收集器,它和ParallelScavenge相比有如下不同:

  1. 算法不同,ParNew採用的是廣度優先遍歷對象,而ParallelScavenge採用的是深度優先。
  2. 沒有UseAdaptiveSizePolicy策略

 

總結

如果是關注吞吐量的應用,採用Throughput收集器是個不錯的選擇。並且可以通過設置

-XX:ParallelGCThreads=N 來設置並行GC線程數。在使用的過程中最好不要手工的指定新生代和老年代的大小,而是指定MaxGCPauseMills 和GCTimeRatio讓其自動調整,以達到最優值。同時設置我們堆大小即可。

CMS收集器

CMS收集器設計的初衷是了消除Throughtput收集器和Serial收集器FullGC週期的長時間停頓。CMD收集器在Minor GC時會暫停所有應用線程,並且以多線程的方式進行垃圾回收。

CMS收集器在FullGC時不再暫停應用線程,而是使用若干個後臺線程定期的對老年代空間進行掃描,及時會後其中不再使用的對象。這種做法使得CMS成爲一個低延遲的收集器。應用線程只在Minor GC以及後臺線程騷烤老年代時發生極其短暫的停頓。應用程序線程停頓的總時長與使用Throughtput收集器比起來短的多。

但是會付出額外的代價,那就是更高的CPU使用:必須有足夠的CPU資源用於後臺運行垃圾收集線程。除此之外,後臺不再進行壓縮整理工作,也就是說堆回逐漸的碎片化。如果CMS的後臺線程無法獲得完成他們任務所需要的CPU資源,或者如果堆變的過度碎片化以至於無法找到連續內存分配先對象,CMS就會蛻化爲Serial收集器的行爲,暫停所有應用線程,使用單線程進行回收,整理老年代空間,之後又恢復到併發運行,再次啓動後臺線程,直到堆變的再次過度碎片化。

開啓標誌:

-XX:+UseConcMarkSweepGC ,-XX:+UseParNewGC

這兩個標誌可以開啓CMS垃圾回收器。

 

Throughput和CMS的選擇

  1. 衡量標準時相應時間或吞吐量,在Throughput收集器和CMS收集器之間做選擇的依據主要是有多少空閒CPU資源能用於運行後臺的併發線程。
  2. 通常情況下,Throughtput收集器的平均響應時間比Concurrent收集器要差,但是在90%影響時間或者99%響應時間的這幾個指標上,Throughput收集器要比Concurrent要好些
  3. 使用Throughput收集器會超負荷進行大量的Full GC時,切換到CMS收集器通常能獲得更低的響應時間
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章