GC回收器 原

一、說明:

concurrent:  併發, 多個線程協同做同一件事情(有狀態);

parallel:        並行, 多個線程各做各的事情(互相間無共享狀態);

二、GC回收器

Java堆內存被劃分爲新生代和年老代,新生代主要使用複製和標記-清除垃圾回收算法,年老代主要使用標記-整理垃圾回收算法。

2.1、Serial

Serial是一個單線程的收集器,採用複製算法。它只會使用一個CPU或一條線程去完成垃圾收集工作,在進行垃圾收集的同時,必須暫停其他所有的工作線程,直到垃圾收集結束。

優點:簡單高效,單個CPU環境來說,沒有線程交互的開銷,可以獲得最高的單線程垃圾收集效率

2.2、ParNew

ParNew是Serial的多線程版本,也使用複製算法,除了使用多線程進行垃圾收集之外,其餘的行爲和Serial收集器完全一樣,ParNew垃圾收集器在垃圾收集過程中同樣也要暫停所有其他的工作線程。

ParNew收集器默認開啓和CPU數目相同的線程數,可以通過-XX:ParallelGCThreads參數來限制垃圾收集器的線程數。

2.3、Parallel Scavenge

多線程回收器,也使用複製算法,是吞吐量優先的垃圾收集器,它還提供一個參數:-XX:+UseAdaptiveSizePolicy,打開之後就不需要手動指定新生代大小(-Xmn)、Eden與Survivor區的比例(-XX:SurvivorRation)、新生代晉升年老代對象年齡(-XX:PretenureSizeThreshold)等細節參數,虛擬機會根據當前系統運行情況收集性能監控信息,動態調整這些參數以達到最大吞吐量,這種方式稱爲GC自適應調節策略,自適應調節策略也是ParallelScavenge收集器與ParNew收集器的一個重要區別。

2.4、Serial Old

Serial Old是Serial垃圾收集器年老代版本,它同樣是個單線程的收集器,使用標記-整理算法。其作用如下:

a、在JDK1.5之前版本中與新生代的Parallel Scavenge收集器搭配使用。

b、作爲年老代中使用CMS收集器的後備垃圾收集方案。

新生代Serial與年老代Serial Old搭配垃圾收集過程圖:

新生代Parallel Scavenge/ParNew與年老代Serial Old搭配垃圾收集過程圖:

2.5、Parallel Old

Parallel Old是Parallel Scavenge的年老代版本,使用多線程的標記-整理算法。

新生代Parallel Scavenge和年老代Parallel Old收集器搭配運行過程圖:

2.6、CMS(Concurrent mark sweep)

CMS是一種年老代垃圾收集器,其最主要目標是獲取最短垃圾回收停頓時間(可以爲交互比較高的程序提高用戶體驗),與其他年老代使用標記-整理算法不同,它使用多線程的標記-清除算法。第一款真正意義上併發垃圾收集器,它第一次實現了讓垃圾收集線程和用戶線程同時工作。

CMS工作機制相比其他的垃圾收集器來說更復雜,整個過程分爲以下4個階段:

a、初始標記:只是標記一下GC Roots能直接關聯的對象,速度很快,仍然需要暫停所有的工作線程。

b、併發標記:進行GC Roots跟蹤的過程,和用戶線程一起工作,不需要暫停工作線程。

c、重新標記:爲了修正在併發標記期間,因用戶程序繼續運行而導致標記產生變動的那一部分對象的標記記錄,仍然需要暫停所有的工作線程。

d、併發清除:清除GC Roots不可達對象,和用戶線程一起工作,不需要暫停工作線程。

由於耗時最長的併發標記和併發清除過程中,垃圾收集線程可以和用戶現在一起併發工作,所以總體上來看CMS收集器的內存回收和用戶線程是一起併發地執行。

CMS收集器工作過程:


CMS收集器缺點:

a、CMS收集器對CPU資源非常敏感

其默認啓動的收集線程數=(CPU數量+3)/4,在用戶程序本來CPU負荷已經比較高的情況下,如果還要分出CPU資源用來運行垃圾收集器線程,會使得CPU負載加重。

b、CMS無法處理浮動垃圾(Floating Garbage),可能會導致Concurrent Mode Failure失敗而導致另一次Full GC

由於CMS收集器和用戶線程併發運行,因此在收集過程中不斷有新的垃圾產生,這些垃圾出現在標記過程之後,CMS無法在本次收集中處理掉它們,只好等待下一次GC時再將其清理掉,這些垃圾就稱爲浮動垃圾。CMS垃圾收集器不能像其他垃圾收集器那樣等待年老代機會完全被填滿之後再進行收集,需要預留一部分空間供併發收集時的使用,可以通過參數-XX:CMSInitiatingOccupancyFraction來設置年老代空間達到多少的百分比時觸發CMS進行垃圾收集,默認是68%。如果在CMS運行期間,預留的內存無法滿足程序需要,就會出現一次ConcurrentMode Failure失敗,此時虛擬機將啓動預備方案,使用Serial Old收集器重新進行年老代垃圾回收。

c、CMS收集器是基於標記-清除算法,因此不可避免會產生大量不連續的內存碎片

如果無法找到一塊足夠大的連續內存存放對象時,將會觸發因此Full GC。CMS提供一個開關參數-XX:+UseCMSCompactAtFullCollection,用於指定在Full GC之後進行內存整理,內存整理會使得垃圾收集停頓時間變長,CMS提供了另外一個參數-XX:CMSFullGCsBeforeCompaction,用於設置在執行多少次不壓縮的Full GC之後,跟着再來一次內存整理。

案例剖析:

1. promotion failed – concurrent mode failure

Minor GC後, 新生代救助空間容納不了剩餘對象,將要放入老年帶,老年帶有碎片或者不能容納這些對象,就產生了concurrent mode failure, 然後進行stop-the-world的Serial Old收集器(CMS就沒什麼意義了)。

解決辦法:-XX:UseCMSCompactAtFullCollection -XX:CMSFullGCBeforeCompaction=5 或者 調大新生代或者救助空間

2. concurrent mode failure

CMS是和業務線程併發運行的,在執行CMS的過程中有業務對象需要在老年帶直接分配,例如大對象,但是老年帶沒有足夠的空間來分配,所以導致concurrent mode failure, 然後需要進行stop-the-world的Serial Old收集器(CMS就沒什麼意義了)。

解決辦法:+XX:CMSInitiatingOccupancyFraction,調大老年帶的空間,+XX:CMSMaxAbortablePrecleanTime

總結一句話:使用標記整理清除碎片和提早進行CMS操作。

2.7、G1

Garbage first垃圾收集器是目前垃圾收集器理論發展的最前沿成果,相比與CMS收集器,G1收集器兩個最突出的改進是:

a、基於標記-整理算法,不產生內存碎片。

b、可以非常精確控制停頓時間,在不犧牲吞吐量前提下,實現低停頓垃圾回收。

G1收集器避免全區域垃圾收集,它把堆內存劃分爲大小固定的幾個獨立區域,並且跟蹤這些區域的垃圾收集進度,同時在後臺維護一個優先級列表,每次根據所允許的收集時間,優先回收垃圾最多的區域。區域劃分和優先級區域回收機制,確保G1收集器可以在有限時間獲得最高的垃圾收集效率。

 

三、常用GC組合

Serial
ParNew + CMS(+ 後備 Serial Old)
ParallelYoung + ParallelOld
G1GC

 

Ref:

https://my.oschina.net/u/1464779/blog/220633

https://my.oschina.net/hosee/blog/674181

https://my.oschina.net/hosee/blog/644618#OSC_h2_6
 

 

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