G1垃圾回收流程
G1的垃圾回收流程主要是從新生代回收開始,新生代回收與并發(fā)標(biāo)記再到混合回收,接下來我們就先來說第一個新生代回收裕膀。
G1 Yong Collection
當(dāng)我們的程序啟動剛開始的時候會默認(rèn)分配新生代5%的空間辑鲤,這里我們假設(shè)分配了8個Region給Eden,1個Region給Survior(只是為了畫圖方便纹因,實際可能Eden對應(yīng)了有好幾十甚至上百個Region)喷屋,那么對應(yīng)的初始內(nèi)存分配如下:
那么當(dāng)我們的Eden區(qū)域裝滿,還是會觸發(fā)新生代的GC辐怕,那么新生代的GC還是會通過復(fù)制算法來進(jìn)行垃圾回收逼蒙,同時系統(tǒng)進(jìn)入“Stop the World”狀態(tài),然后把Eden區(qū)中的對應(yīng)的Region里存活的對象拷貝到S1對應(yīng)的Region中寄疏,接著回收掉Eden對應(yīng)的Region中的垃圾對象。
那么新生代對象什么時候進(jìn)入老年代呢僵井?跟之前一樣陕截,還是這么幾個條件:1)對象在新生代躲過了多次的垃圾回收,達(dá)到了一定的年齡批什,就會進(jìn)入老年代农曲。可以通過參數(shù)“-XX:MaxTenuringThreshold”進(jìn)行年齡的設(shè)置
2)動態(tài)年齡規(guī)則判斷驻债,如果一旦發(fā)現(xiàn)某個新生代GC過后乳规,同年齡的存活對象超過了Survior的50%,比如此時有1歲的合呐,2歲的暮的,3歲的,5歲的淌实,發(fā)現(xiàn)3歲的對象大小總和已經(jīng)超過了Survior的50%冻辩。那么3歲及以上的對象都會全部進(jìn)入老年代
所以經(jīng)過一段時間新生代的使用和垃圾回收后,總有一些對象會進(jìn)入老年代拆祈,如下圖:
此時大家可能會疑惑恨闪?之前不是說我們有大對象根據(jù)JVM的空間擔(dān)保原則也會直接進(jìn)入老年代嗎?
實際根據(jù)G1的分配原則放坏,G1會提供專門的Region來存放大對象咙咽,而不是讓大對象直接進(jìn)入老年代的Region中,G1中如何判斷大對象是根據(jù)Region的大小來的淤年,如果一個對象的大小已經(jīng)超過Region大小的50%了钧敞,那么就會被放入大對象專門的Region中,這種Region我們叫humongous互亮,如下圖:
那肯定會有人問了犁享,這個humongous區(qū)域的大對象什么時候被回收呢?它既不屬于新生代與不屬于老年代豹休,什么時候觸發(fā)垃圾回收進(jìn)行回收炊昆?
其實很簡單,在新生代和老年代回收的時候,就會順帶著對大對象一并回收了凤巨,所以這就是G1內(nèi)存模型下對大對象的分配和回收的策略视乐。
注意:
在G1進(jìn)行新生代垃圾回收的同時還會做一件事情就是“初始標(biāo)記”::僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象,為下一階段并發(fā)標(biāo)記做準(zhǔn)備(跟之前的CMS垃圾回收過程類似)
G1 Yong Collection + Concunrrent Mark
當(dāng)G1新生代垃圾回收結(jié)束后敢茁,緊接著開始進(jìn)入并發(fā)標(biāo)記階段:從GC Root開始對堆中對象進(jìn)行可達(dá)性分析佑淀,遞歸掃描整個堆里的對象圖,找出要回收的對象彰檬,這階段耗時較長伸刃,但可與用戶程序并發(fā)執(zhí)行。
而且JVM會對并發(fā)標(biāo)記階段對對象做出的一些修改記錄起來逢倍,比如哪個對象被新建了捧颅,哪個對象失去引用了,如下圖:
G1 Mixed Collection
G1有一個參數(shù):“-XX:InitiatingHeapOccupancyPercent”,默認(rèn)值是45%
也就是說,當(dāng)老年代的大小占據(jù)了堆內(nèi)存的45%的Region時较雕,此時就會觸發(fā)一個新生代和老年代的混合回收階段碉哑,對E S 0 H進(jìn)行全面回收。
該階段一旦觸發(fā)會導(dǎo)致系統(tǒng)進(jìn)入STW亮蒋,同時進(jìn)行最后一個標(biāo)記:
- 最終標(biāo)記階段:會根據(jù)并發(fā)標(biāo)記階段記錄的對象修改扣典,最終標(biāo)記哪些對象是存活,哪些對象是垃圾
此時老年代也是根據(jù)標(biāo)記-復(fù)制算法來進(jìn)行回收的慎玖,會將標(biāo)記存活的對象拷貝到新的Region中作為老年代區(qū)域:
注意我們上面說過一個參數(shù):-XX:MaxGCPauseMillis=time 指定收集的停頓時間贮尖,默認(rèn)是200ms
由于混合回收是一個比較耗時的操作,那么根據(jù)G1的特點可以指定收集停頓時間凄吏,為了保證停頓時間這個目標(biāo)远舅,JVM會從新生代、老年代痕钢、以及大對象H區(qū)挑選一部分Region進(jìn)行拷貝回收图柏,如果回收不完,后續(xù)再進(jìn)行回收任连,一部分一部分回收直到回收完畢蚤吹。但是一次回收停頓的時長保證再200ms。
這里有一個參數(shù):“-XX:G1MixedGCCountTarget”随抠,可以設(shè)置在一次混合回收的過程中裁着,最后一個階段執(zhí)行幾次混合回收,默認(rèn)值是8次拱她!這樣設(shè)置的目的也是能讓每次回收停頓的時長記得到保證同時又能間隙的讓系統(tǒng)接著運行二驰。
同時還有一個參數(shù):“-XX:G1HeapWastePercent”,默認(rèn)值是5%,意思是當(dāng)混合回收的時候秉沼,一旦空閑出來的Region數(shù)量達(dá)到了堆內(nèi)存的5%桶雀,此時就會立即停止混合回收矿酵。
Full GC
當(dāng)在進(jìn)行混合回收的過程中,由于無論是新生代還是老年代都是基于復(fù)制算法進(jìn)行的矗积,都需要將各個Region中的存活對象拷貝到別的Region中全肮,此時如果一旦出現(xiàn)拷貝的過程中發(fā)現(xiàn)沒有空閑的Region可以進(jìn)行存儲了,就會觸發(fā)一次失敿贰辜腺!那么這個時候系統(tǒng)會立馬切換為我們的Seiral收集器進(jìn)行單線程的標(biāo)記、清理和壓縮整理乍恐,該過程就變得非常的慢了评疗!
這里我們可以小結(jié)下各個收集器的FullGC:
-
SerialGC
新生代內(nèi)存不足發(fā)生的垃圾收集 - minor gc
老年代內(nèi)存不足發(fā)生的垃圾收集 - full gc
-
ParallelGC
新生代內(nèi)存不足發(fā)生的垃圾收集 - minor gc
老年代內(nèi)存不足發(fā)生的垃圾收集 - full gc
-
CMS
新生代內(nèi)存不足發(fā)生的垃圾收集 - minor gc
老年代內(nèi)存不足,觸發(fā)Concurrent Mode Failure時觸發(fā)Full GC
-
G1
新生代內(nèi)存不足發(fā)生的垃圾收集 - minor gc
老年代內(nèi)存不足禁熏,無多余Region可供拷貝壤巷,觸發(fā)FullGC