深刻理解java虛擬機【Java虛擬機垃圾收集器】

Java堆內存被劃分爲新生代和年老代兩部分,新生代主要使用複製和標記-清除垃圾回收算法,年老代主要使用標記-整理垃圾回收算法,所以java虛擬中針對新生代和年老代分別提供了多種不一樣的垃圾收集器,JDK1.6中Sun HotSpot虛擬機的垃圾收集器以下:
java

圖中若是兩個垃圾收集器直接有連線,則代表這兩個垃圾收集器能夠搭配使用。web

(1).Serial垃圾收集器:算法

Serial是最基本、歷史最悠久的垃圾收集器,使用複製算法,曾經是JDK1.3.1以前新生代惟一的垃圾收集器。多線程

Serial是一個單線程的收集器,它不只僅只會使用一個CPU或一條線程去完成垃圾收集工做,而且在進行垃圾收集的同時,必須暫停其餘全部的工做線程,直到垃圾收集結束。併發

Serial垃圾收集器雖然在收集垃圾過程當中須要暫停全部其餘的工做線程,可是它簡單高效,對於限定單個CPU環境來講,沒有線程交互的開銷,能夠得到最高的單線程垃圾收集效率,所以Serial垃圾收集器依然是java虛擬機運行在Client模式下默認的新生代垃圾收集器。性能

(2).ParNew垃圾收集器:spa

ParNew垃圾收集器實際上是Serial收集器的多線程版本,也使用複製算法,除了使用多線程進行垃圾收集以外,其他的行爲和Serial收集器徹底同樣,ParNew垃圾收集器在垃圾收集過程當中一樣也要暫停全部其餘的工做線程。線程

ParNew收集器默認開啓和CPU數目相同的線程數,能夠經過-XX:ParallelGCThreads參數來限制垃圾收集器的線程數。日誌

ParNew雖然是除了多線程外和Serial收集器幾乎徹底同樣,可是ParNew垃圾收集器是不少java虛擬機運行在Server模式下新生代的默認垃圾收集器。orm

(3).Parallel Scavenge收集器:

Parallel Scavenge收集器也是一個新生代垃圾收集器,一樣使用複製算法,也是一個多線程的垃圾收集器,它重點關注的是程序達到一個可控制的吞吐量(Thoughput,CPU用於運行用戶代碼的時間/CPU總消耗時間,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)),高吞吐量能夠最高效率地利用CPU時間,儘快地完成程序的運算任務,主要適用於在後臺運算而不須要太多交互的任務。

Parallel Scavenge收集器提供了兩個參數用於精準控制吞吐量:

a.-XX:MaxGCPauseMillis:控制最大垃圾收集停頓時間,是一個大於0的毫秒數。

b.-XX:GCTimeRation:直接設置吞吐量大小,是一個大於0小於100的整數,也就是程序運行時間佔總時間的比率,默認值是99,即垃圾收集運行最大1%(1/(1+99))的垃圾收集時間。

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

(4).Serial Old收集器:

Serial Old是Serial垃圾收集器年老代版本,它一樣是個單線程的收集器,使用標記-整理算法,這個收集器也主要是運行在Client默認的java虛擬機默認的年老代垃圾收集器。

在Server模式下,主要有兩個用途:

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

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

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

新生代Parallel Scavenge收集器與ParNew收集器工做原理相似,都是多線程的收集器,都使用的是複製算法,在垃圾收集過程當中都須要暫停全部的工做線程。

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

(5).Parallel Old收集器:

Parallel Old收集器是Parallel Scavenge的年老代版本,使用多線程的標記-整理算法,在JDK1.6纔開始提供。

在JDK1.6以前,新生代使用ParallelScavenge收集器只能搭配年老代的Serial Old收集器,只能保證新生代的吞吐量優先,沒法保證總體的吞吐量,Parallel Old正是爲了在年老代一樣提供吞吐量優先的垃圾收集器,若是系統對吞吐量要求比較高,能夠優先考慮新生代Parallel Scavenge和年老代Parallel Old收集器的搭配策略。

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

(6).CMS收集器:

Concurrent mark sweep(CMS)收集器是一種年老代垃圾收集器,其最主要目標是獲取最短垃圾回收停頓時間,和其餘年老代使用標記-整理算法不一樣,它使用多線程的標記-清除算法。

最短的垃圾收集停頓時間能夠爲交互比較高的程序提升用戶體驗,CMS收集器是Sun HotSpot虛擬機中第一款真正意義上併發垃圾收集器,它第一次實現了讓垃圾收集線程和用戶線程同時工做。

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 ModeFailure失敗而致使另外一次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以後,跟着再來一次內存整理。

(7).G1收集器:

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

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

b.能夠很是精確控制停頓時間,在不犧牲吞吐量前提下,實現低停頓垃圾回收。

G1收集器避免全區域垃圾收集,它把堆內存劃分爲大小固定的幾個獨立區域,而且跟蹤這些區域的垃圾收集進度,同時在後臺維護一個優先級列表,每次根據所容許的收集時間,優先回收垃圾最多的區域。

區域劃分和優先級區域回收機制,確保G1收集器能夠在有限時間得到最高的垃圾收集效率。

Java虛擬機經常使用的垃圾收集器相關參數以下:

 

參數

描述

UseSerialGC

虛擬機運行在Client模式的默認值,打開此開關參數後,
使用Serial+Serial Old收集器組合進行垃圾收集。

UseParNewGC

打開此開關參數後,使用ParNew+Serial Old收集器組合進
行垃圾收集。

UseConcMarkSweepGC

打開此開關參數後,使用ParNew+CMS+Serial Old收集器組
合進行垃圾收集。Serial Old做爲CMS收集器出現Concurrent 
Mode Failure的備用垃圾收集器。

UseParallelGC

虛擬機運行在Server模式的默認值,打開此開關參數後,
使用Parallel Scavenge+Serial Old收集器組合進行垃圾收集。

UseParallelOldGC

打開此開關參數後,
使用Parallel Scavenge+Parallel Old收集器組合進行垃圾收集。

SurvivorRation

新生代內存中Eden區域與Survivor區域容量比值,默認是8,即
Eden:Survivor=8:1.

PretenureSizeThreshold

直接晉升到年老代的對象大小,設置此參數後,超過該大小的
對象直接在年老代中分配內存。

MaxTenuringThreshold

直接晉升到年老代的對象年齡,每一個對象在一次Minor GC以後還
存活,則年齡加1,當年齡超過該值時進入年老代。

UseAdaptiveSizePolicy

java虛擬機動態自適應策略,動態調全年老代對象年齡和各個區域大小。

HandlePromotionFailure

是否容許擔保分配內存失敗,即整個年老代空間不足,而整個新生代中Eden和Survivor對象都存活的極端狀況。

ParallelGCThreads

設置並行GC時進行內存回收的線程數。

GCTimeRation

Parallel Scavenge收集器運行時間佔總時間比率。

MaxGCPauseMillis

Parallel Scavenge收集器最大GC停頓時間。

CMSInitiatingOccupancyFraction

設置CMS收集器在年老代空間被使用多少百分比以後觸發垃圾收集,默認是68%。

UseCMSCompactAtFullCollection

設置CMS收集器在完成垃圾收集以後是否進行一次內存整理。

CMSFullGCsBeforeCompaction

設置CMS收集器在進行多少次垃圾收集以後才進行一次內存整理。

java虛擬機的-XX:+PrintGCDetails參數能夠打印垃圾收集器的日誌信息。

 

-verbose:gc能夠查看Java虛擬機垃圾收集結果。

相關文章
相關標籤/搜索