24-一步一圖帶你理清G1垃圾回收流程

G1垃圾回收流程

image

G1的垃圾回收流程主要是從新生代回收開始,新生代回收與并發(fā)標(biāo)記再到混合回收,接下來我們就先來說第一個(gè)新生代回收。

G1 Yong Collection

當(dāng)我們的程序啟動剛開始的時(shí)候會默認(rèn)分配新生代5%的空間,這里我們假設(shè)分配了8個(gè)Region給Eden,1個(gè)Region給Survior(只是為了畫圖方便,實(shí)際可能Eden對應(yīng)了有好幾十甚至上百個(gè)Region),那么對應(yīng)的初始內(nèi)存分配如下:

image

那么當(dāng)我們的Eden區(qū)域裝滿,還是會觸發(fā)新生代的GC,那么新生代的GC還是會通過復(fù)制算法來進(jìn)行垃圾回收,同時(shí)系統(tǒng)進(jìn)入“Stop the World”狀態(tài),然后把Eden區(qū)中的對應(yīng)的Region里存活的對象拷貝到S1對應(yīng)的Region中,接著回收掉Eden對應(yīng)的Region中的垃圾對象。

image

那么新生代對象什么時(shí)候進(jìn)入老年代呢?跟之前一樣,還是這么幾個(gè)條件:1)對象在新生代躲過了多次的垃圾回收,達(dá)到了一定的年齡,就會進(jìn)入老年代??梢酝ㄟ^參數(shù)“-XX:MaxTenuringThreshold”進(jìn)行年齡的設(shè)置

2)動態(tài)年齡規(guī)則判斷,如果一旦發(fā)現(xiàn)某個(gè)新生代GC過后,同年齡的存活對象超過了Survior的50%,比如此時(shí)有1歲的,2歲的,3歲的,5歲的,發(fā)現(xiàn)3歲的對象大小總和已經(jīng)超過了Survior的50%。那么3歲及以上的對象都會全部進(jìn)入老年代

所以經(jīng)過一段時(shí)間新生代的使用和垃圾回收后,總有一些對象會進(jìn)入老年代,如下圖:

image

此時(shí)大家可能會疑惑?之前不是說我們有大對象根據(jù)JVM的空間擔(dān)保原則也會直接進(jìn)入老年代嗎?

實(shí)際根據(jù)G1的分配原則,G1會提供專門的Region來存放大對象,而不是讓大對象直接進(jìn)入老年代的Region中,G1中如何判斷大對象是根據(jù)Region的大小來的,如果一個(gè)對象的大小已經(jīng)超過Region大小的50%了,那么就會被放入大對象專門的Region中,這種Region我們叫humongous,如下圖:

image

那肯定會有人問了,這個(gè)humongous區(qū)域的大對象什么時(shí)候被回收呢?它既不屬于新生代與不屬于老年代,什么時(shí)候觸發(fā)垃圾回收進(jìn)行回收?

其實(shí)很簡單,在新生代和老年代回收的時(shí)候,就會順帶著對大對象一并回收了,所以這就是G1內(nèi)存模型下對大對象的分配和回收的策略。

注意:

在G1進(jìn)行新生代垃圾回收的同時(shí)還會做一件事情就是“初始標(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á)性分析,遞歸掃描整個(gè)堆里的對象圖,找出要回收的對象,這階段耗時(shí)較長,但可與用戶程序并發(fā)執(zhí)行。

而且JVM會對并發(fā)標(biāo)記階段對對象做出的一些修改記錄起來,比如哪個(gè)對象被新建了,哪個(gè)對象失去引用了,如下圖:

image

G1 Mixed Collection

G1有一個(gè)參數(shù):“-XX:InitiatingHeapOccupancyPercent”,默認(rèn)值是45%

也就是說,當(dāng)老年代的大小占據(jù)了堆內(nèi)存的45%的Region時(shí),此時(shí)就會觸發(fā)一個(gè)新生代和老年代的混合回收階段,對E S 0 H進(jìn)行全面回收。

該階段一旦觸發(fā)會導(dǎo)致系統(tǒng)進(jìn)入STW,同時(shí)進(jìn)行最后一個(gè)標(biāo)記:

  • 最終標(biāo)記階段:會根據(jù)并發(fā)標(biāo)記階段記錄的對象修改,最終標(biāo)記哪些對象是存活,哪些對象是垃圾

此時(shí)老年代也是根據(jù)標(biāo)記-復(fù)制算法來進(jìn)行回收的,會將標(biāo)記存活的對象拷貝到新的Region中作為老年代區(qū)域:

image

注意我們上面說過一個(gè)參數(shù):-XX:MaxGCPauseMillis=time 指定收集的停頓時(shí)間,默認(rèn)是200ms

由于混合回收是一個(gè)比較耗時(shí)的操作,那么根據(jù)G1的特點(diǎn)可以指定收集停頓時(shí)間,為了保證停頓時(shí)間這個(gè)目標(biāo),JVM會從新生代、老年代、以及大對象H區(qū)挑選一部分Region進(jìn)行拷貝回收,如果回收不完,后續(xù)再進(jìn)行回收,一部分一部分回收直到回收完畢。但是一次回收停頓的時(shí)長保證再200ms。

這里有一個(gè)參數(shù):“-XX:G1MixedGCCountTarget”,可以設(shè)置在一次混合回收的過程中,最后一個(gè)階段執(zhí)行幾次混合回收,默認(rèn)值是8次!這樣設(shè)置的目的也是能讓每次回收停頓的時(shí)長記得到保證同時(shí)又能間隙的讓系統(tǒng)接著運(yùn)行。

同時(shí)還有一個(gè)參數(shù):“-XX:G1HeapWastePercent”,默認(rèn)值是5%,意思是當(dāng)混合回收的時(shí)候,一旦空閑出來的Region數(shù)量達(dá)到了堆內(nèi)存的5%,此時(shí)就會立即停止混合回收。

Full GC

當(dāng)在進(jìn)行混合回收的過程中,由于無論是新生代還是老年代都是基于復(fù)制算法進(jìn)行的,都需要將各個(gè)Region中的存活對象拷貝到別的Region中,此時(shí)如果一旦出現(xiàn)拷貝的過程中發(fā)現(xiàn)沒有空閑的Region可以進(jìn)行存儲了,就會觸發(fā)一次失??!那么這個(gè)時(shí)候系統(tǒng)會立馬切換為我們的Seiral收集器進(jìn)行單線程的標(biāo)記、清理和壓縮整理,該過程就變得非常的慢了!

這里我們可以小結(jié)下各個(gè)收集器的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時(shí)觸發(fā)Full GC

  • G1

    新生代內(nèi)存不足發(fā)生的垃圾收集 - minor gc

    老年代內(nèi)存不足,無多余Region可供拷貝,觸發(fā)FullGC

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容