【大內(nèi)存服務(wù)GC實(shí)踐】- 一文看懂G1GC垃圾回收器


背景介紹


G1核心數(shù)據(jù)結(jié)構(gòu)
1. Region

2. RememberedSet(RSet)和Card Table
2.1 RSet是什么樣的數(shù)據(jù)結(jié)構(gòu)呢?

sparse per-region-table (PRT),從字面意思來看表示這個(gè)RSet是一個(gè)稀疏的集合。具體實(shí)現(xiàn)使用HashMap方式記錄引用關(guān)系,其中Map的key是引用Region,value是一個(gè)List,List中存儲(chǔ)引用Region中的引用Card列表。上文有過介紹。
fine-grained PRT,還是使用HashMap方式記錄引用關(guān)系,其中Map的key是引用Region,但value不再是List,而是一個(gè)bitmap,bit位為1表示對(duì)應(yīng)Card是引用Card,否則不是引用Card。
coarse-grained bitmap,從字面意思可以看出來這就是一個(gè)bitmap,不過bitmap中每個(gè)bit位引用粒度不再是Card,而是Region。如果bit位值為1,表示這個(gè)Region是引用Region,即這個(gè)Region中有對(duì)象引用了該Region中的對(duì)象。
很顯然,上述3種實(shí)現(xiàn)方式中,spase PRT和fine-grained PRT都是精確到Card,而coarse-grained bitmap是精確到Region。


G1核心工作流程


1. Young GC核心流程
從GC Roots開始標(biāo)記直接引用的新生代對(duì)象。 基于RSet標(biāo)記跨代引用的新生代對(duì)象。

2. Concurrent Marking Cycle核心流程

初始標(biāo)記(Initial Marking):初始化標(biāo)記是伴隨一次普通的YGC發(fā)生的,從GC Root開始標(biāo)記直接可達(dá)的對(duì)象。
并發(fā)標(biāo)記( Concurrent Marking):這個(gè)階段標(biāo)記線程和應(yīng)用線程并發(fā)工作,遍歷整堆所有可達(dá)對(duì)象并標(biāo)記。這個(gè)階段需要特別關(guān)注并發(fā)標(biāo)記可能產(chǎn)生的"漏標(biāo)"問題,G1使用Snapshot AT Begining(簡稱SATB)算法避免漏標(biāo)問題發(fā)生,這和CMS完全不同。3.4小節(jié)深入介紹。
重新標(biāo)記( Remark) :標(biāo)記那些在并發(fā)標(biāo)記階段發(fā)生變化的對(duì)象,將被回收。 清理( Cleanup ):釋放沒有存活對(duì)象的Region。
3.?Mixed GC核心流程
4. 并發(fā)標(biāo)記階段對(duì)象"漏標(biāo)"問題解法 - SATB算法
4.1 對(duì)象漏標(biāo)簡介

對(duì)象A已經(jīng)被標(biāo)記為黑色,表示為A為活躍對(duì)象且所有它引用的對(duì)象也完成標(biāo)記。 對(duì)象B被標(biāo)記為灰色,表示B對(duì)象是活躍對(duì)象,但是它關(guān)聯(lián)的對(duì)象還沒有被完全標(biāo)記完。 對(duì)象C是白色,表示還沒有被標(biāo)記。
objB.fieldC?=?null;objA.filedC = C;
4.2 SATB算法思想簡介
并發(fā)標(biāo)記之前先給Region內(nèi)存打個(gè)快照,標(biāo)記線程基于這個(gè)快照獨(dú)立進(jìn)行標(biāo)記。應(yīng)用線程不會(huì)直接修改這個(gè)快照中的對(duì)象,也就是說應(yīng)用線程不會(huì)干擾標(biāo)記線程的工作。 應(yīng)用線程新分配的對(duì)象都認(rèn)為是活躍對(duì)象,實(shí)際在下一個(gè)并發(fā)標(biāo)記周期進(jìn)行標(biāo)記。上文說過漏標(biāo)發(fā)生的第一種場景是"應(yīng)用線程在并發(fā)標(biāo)記過程中新生成的活躍對(duì)象因?yàn)槟承┰驔]有被標(biāo)記線程標(biāo)記",那如果能夠?qū)?biāo)記階段新分配的對(duì)象全都集合到一起,這些對(duì)象全部都標(biāo)記為活躍對(duì)象(實(shí)際肯定會(huì)有部分垃圾對(duì)象,將垃圾對(duì)象標(biāo)記為活躍對(duì)象不影響程序正確性)就可以解決這個(gè)問題。 并發(fā)標(biāo)記過程中已存在對(duì)象的引用關(guān)系變更在Remark階段單獨(dú)進(jìn)行處理。上文介紹了漏標(biāo)發(fā)生的第二種場景,為了解決這個(gè)場景引入的漏標(biāo)問題,可以將引用關(guān)系變更分解為舊的引用關(guān)系先刪除,新的引用關(guān)系生成兩個(gè)步驟,只要破壞任何一個(gè)步驟就可以防止漏標(biāo)發(fā)生。因此有兩種針對(duì)性解法:
在并發(fā)標(biāo)記階段如果有新引用關(guān)系生成,就記錄下來,Remark階段進(jìn)行重標(biāo)記,這個(gè)破壞了步驟二,即黑色對(duì)象重新引用了白色對(duì)象,就記錄下來重新掃描黑色對(duì)象,將其引用的所有對(duì)象都標(biāo)記成存活對(duì)象。這個(gè)就是CMS垃圾回收器使用的增量更新算法。 在并發(fā)標(biāo)記階段如果有引用關(guān)系被刪除,就記錄下來,Remark階段對(duì)這些引用關(guān)系被刪除的重標(biāo)記,這個(gè)破壞了步驟一,即灰色對(duì)象斷開了白色對(duì)象引用的時(shí)候,記錄下來,后面重新把這個(gè)白色對(duì)象標(biāo)記成存活對(duì)象。這個(gè)就是G1垃圾回收器使用的算法。
4.3 SATB算法實(shí)現(xiàn)



satb_mark_queue),在remark階段會(huì)掃描這個(gè)隊(duì)列,通過這種方式,舊的引用所指向的對(duì)象就會(huì)被標(biāo)記上,其子孫也會(huì)被遞歸標(biāo)記上,這樣就不會(huì)漏標(biāo)記任何對(duì)象,snapshot的完整性也就得到了保證。
4.4 SATB算法 vs Incremental Update算法


全文總結(jié)
評(píng)論
圖片
表情
