JVM探祕4---垃圾收集器介紹

Java虛擬機有不少垃圾收集器算法

下面先來了解HotSpot虛擬機中的7種垃圾收集器:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1,先介紹一些垃圾收集的相關概念,再介紹它們的主要特色、應用場景、以及一些設置參數和基本運行原理。多線程

常見的垃圾收集器關係圖以下:併發

若是兩個收集器直接有連線,則表示能夠搭配使用,而G1收集器是不區分老年代和新生代的,因此不須要和其餘收集器搭配,其餘的則只能用於老年代或是新生代。jvm

下面針對每一個收集器逐個分析:性能

1.Serial收集器(新生代收集器)

Serial是歷史最悠久的收集器,也一個單線程收集器,只有一個CPU或一個線程來完成垃圾收集工做,並且Serial收集器在垃圾回收的時候會暫停全部工做線程,直到垃圾回收結束再恢復工做線程。優化

2.ParNew收集器(新生代收集器)

ParNew收集器是Serial收集器的多線程版本,工做方式和工做原理徹底一致,只是ParNew收集器會建立多個線程來進行垃圾回收工做。不過若是是在單CPU的狀況下,ParNew收集器的性能反而不必定有Serial收集器好,由於ParNew還有額外的線程之間切換的消耗,若是是多CPU的狀況下,則效果更好點,因此ParNew默認開啓的垃圾收集的線程個數一個和CPU的數量是1:1的比例,在線程數比CPU數量小的狀況下,ParNew的性能仍是很可觀的。線程

3.Parallel Scavenge收集器(新生代收集器)

Parallel Scavenage收集器是採用了複製算法,且是並行的多線程收集器,它的特色是不關注收集器用戶線程的停頓時間,而是關注達到一個可控制的吞吐量。吞吐量爲CPU用於運行用戶線程的代碼與CPU總耗時的比例,好比JVM工做100分鐘,垃圾回收使用1分鐘,用戶線程使用99分鐘,則吞吐量就是99%,Paramllel Scavenge收集器提供兩個參數用戶控制吞吐量。分別是控制最大垃圾收集停頓時間 -XX:MaxGCPauseMillis參數、設置吞吐量大小-XX:GCTimeRatio對象

若是設置停頓時間太短,則垃圾收集時花費的時間不會超過最大值,可是若是停頓時間過於小,就會致使新生代的垃圾回收的頻率會增高,原本能夠10秒收集一次,停頓100毫秒,變成了5秒收集一次,每次停頓70毫秒,雖然停頓時間下降了,可是總體的吞吐量卻降低了。blog

而若是直接設置吞吐量,則收集器會按照吞吐量設置的值來分配總體的垃圾收集的時間來進行收集垃圾。遞歸

4.Serial Old收集器(老年代收集器)

Serial Old是Serial收集器的老年代版本,也是單線程的,使用的「標記-整理」算法

5.Parallel Old收集器(老年代收集器)

Parallel Old是Paraller Scavenge收集器的老年代版本,使用多線程和「標記-整理」算法,只能與Parallel Scavenge收集器搭配使用

6.CMS收集器(老年代收集器)

CMS是目前最經常使用的收集器,主要是和ParNew來搭配使用。CMS(Concurrent  Mark Sweep)從名字能夠看出是併發的標記清除垃圾收集器,過程比較複雜。特色是以獲取最短回收停頓時間爲目標,整個過程大體分爲四個步驟:

初始標記-》併發標記-》併發預處理-》從新標記-》併發清除

初始標記:標記一下GC Roots可以關聯到的對象,速度很快,可是也會使用戶線程短暫的中止,只是停頓的時間很快。

併發標記:併發標記耗時較長,可是能夠和用戶線程併發進行,不須要使用戶暫停,不過會消耗CPU的資源,會影響到用戶線程的吞吐量,CMS默認會開啓回收線程的數量是CPU個數+3/4,好比cpu是1的狀況下,會啓動一個線程,若是cpu是5的話,就會啓動2個線程,併發標記會根據初始標記出來的經過GC ROOTS關聯到的對象,而後經過遞歸繼續標記這些對象能夠達到的對象

從新標記:暫停用戶線程,從新在堆中進行可達性分析,標記存貨對象,此時的存活又沒有被標記的對象不多了,因此用戶線程停頓的時間也較短

併發清除:和用戶線程併發進行,清除沒有被標記的對象

另外CMS收集器沒法處理浮動垃圾,由於cms和用戶線程是併發進行的,在垃圾回收的同時用戶線程可能會產生新的垃圾,這就使得本次垃圾回收沒法清除,會留到下一次回收。另外cms是和用戶線程並行處理的,因此在工做時還須要預留足夠的內存空間在用戶線程使用,所以cms收集器不能像其餘收集器同樣等到老年代幾乎滿了纔開始進行垃圾回收,須要預留一部分給用戶線程使用,默認狀況下在老年代使用了68%空間以後就會觸發垃圾回收。固然也能夠經過設置jvm參數-XX:CMSInitatingOccupancyFraction來設置觸發的百分比。

而若是CMS沒有預留足夠空間給用戶線程的話,會出現「Concurrent Mode Failure」失敗,這是虛擬機就會啓動預備方案,臨時啓用Serial Old收集器來從新對老年代進行一次垃圾收集,這樣就會影響性能。

並且因爲CMS是經過標記清除算法,因此會產生大量的內存碎片,就會出現老年代內存空間足夠可是沒法建立一些大對象,就會提早觸發一次Full GC。而CMS就提供了兩個JVM參數用來優化這個問題,分別是:

-XX:+UseCMSCompactAtFullCollect參數,使得在實現Full GC以後額外進行一次內存整理,這樣就沒有了內存碎片,可是涉及到內存整理,因此停頓時間變長了

-XX:CMSFullGCsBeforeCompaction參數,設置在執行多少次不壓縮的Full GC以後進行一次內存整理。

7.G1收集器  (新生代、老年代收集器)

G1收集器沒有新生代和老年代的區分,G1實現了不犧牲吞吐量的狀況下又達到了低停頓的效果。主要是由於G1不像其餘收集器同樣針對整個新生代或是老年代進行垃圾回收,並且將整個堆內存劃分紅了多個大小同樣的獨立區域,並跟蹤每一個區域的垃圾狀況,而且有一個優先列表,優先回收垃圾最多的區域。

相關文章
相關標籤/搜索