G1設(shè)計(jì)的目標(biāo)是讓stop the world的時(shí)間是可預(yù)測(cè)和可配置的。C1垃圾回收器是軟實(shí)時(shí),低延遲的垃圾回收器,你可以設(shè)置你需要的性能目標(biāo)。它解決了CMS中空間碎片的問題,同時(shí)因?yàn)镚1在低延遲,高吞吐量方面都比較好,所以在JDK9取代了默認(rèn)的Parallel GC 關(guān)注吞吐量的組合成為默認(rèn)的垃圾回收器,而CMS在Jdk9被移除了。
G1不要求將年輕代和老年代用連續(xù)的空間來(lái)實(shí)現(xiàn),堆會(huì)被劃分成一系列的小resion,通常默認(rèn)是2048塊,任何一個(gè)region可能是eden區(qū),survivor區(qū),或者是老年代區(qū),但是不能一個(gè)region有多個(gè)區(qū),只能是其中一個(gè)。每塊Region取值范圍為1M到32M,并且只能是2的n次冪,可以通過(guò)虛擬機(jī)參數(shù):
-XX:G1HeapRegionSize來(lái)設(shè)置大小,所有的eden和survivor區(qū)的總和就是年輕代的大小,所有老年代的總和就是老年代的大小。如下圖:

這種化分區(qū)域的方式,使得垃圾回收的時(shí)候,不需要對(duì)很大的一塊區(qū)域進(jìn)行垃圾回收(比如serial系列垃圾收集器,要么整塊年輕代,要么整個(gè)堆進(jìn)行回收),而是逐步的進(jìn)行回收,僅僅回收一部分region,即回收region的整數(shù)倍區(qū)域。年輕代回收的時(shí)候,會(huì)stop the world,當(dāng)存在跨代引用的時(shí)候會(huì)包含部分的老年代被回收,這一次回收的部分稱為回收集。如下圖,被框了(有黑色框)的部分就是這一次垃圾回收會(huì)處理的region。

G1可以評(píng)估每一個(gè)region存活對(duì)象的數(shù)量和回收該區(qū)域所需要的時(shí)間經(jīng)驗(yàn)值,來(lái)維護(hù)一個(gè)優(yōu)先級(jí)列表,每次根據(jù)用戶設(shè)置的停頓時(shí)間(可以使用參數(shù):-XX:MaxGCPauseMillis設(shè)置),優(yōu)先回收包含比較多垃圾對(duì)象的regions,這也是該垃圾回收器名稱Garbage first的由來(lái)。
可以使用JVM參數(shù) -XX:+UserG1GC來(lái)啟用G1垃圾回收器。隨著服務(wù)啟動(dòng),處理請(qǐng)求,年輕代空間被使用完,就會(huì)stop the world,進(jìn)行垃圾回收處理,將所有存活的對(duì)象,拷貝到survivor區(qū),這個(gè)處理階段被稱為疏散階段,這個(gè)階段和其他垃圾回收器,比如serial,Parnew等非常相似。除了上述的年輕代,老年代,survivor區(qū)域外,G1中還有一種特殊的區(qū)域,humongous,用來(lái)存儲(chǔ)大對(duì)象用的,當(dāng)需要分配一個(gè)連續(xù)超過(guò)region一半的連續(xù)大對(duì)象的時(shí)候,那么就會(huì)使用Humongous這塊區(qū)域,這塊區(qū)域的會(huì)被當(dāng)作老年代來(lái)處理。
卡表:將整個(gè)堆劃分為大小512KB的小內(nèi)存,被實(shí)現(xiàn)為一個(gè)簡(jiǎn)單的字節(jié)數(shù)組byte[],即卡表的每個(gè)標(biāo)記項(xiàng)為1個(gè)字節(jié)。有相應(yīng)的索引值index,0,1,2...., 那么對(duì)應(yīng)的地址就為0,512,1024...
跨代引用或者混合GC中老年代跨region引用的處理:
使用remembered set避免全堆掃描,每一個(gè)region都維護(hù)一個(gè)remembered set,這些結(jié)構(gòu)會(huì)記錄別的regionA指向該regionB的引用地址信息,并記錄regionA的卡表信息,就regionA中哪個(gè)卡表索引區(qū)域的對(duì)象引用了regionB的對(duì)象,標(biāo)記為dirty。remembered set本質(zhì)上是一個(gè)hash結(jié)構(gòu),key存的時(shí)候region的起始地址,value是卡表索引號(hào)集合(被標(biāo)記dirty的卡表索引)。這些額外的存儲(chǔ)內(nèi)存,大約要損耗堆內(nèi)存的10%到20%的大小,額外執(zhí)行的負(fù)載也相對(duì)比較高。

寫屏障
每次reference類型數(shù)據(jù)的寫操作,都會(huì)產(chǎn)生一個(gè)write barrier 中斷操作,然后檢查將要寫入引用的對(duì)象是否和該reference類型數(shù)據(jù)在不同region,如果不同,那么把相關(guān)引用信息,記錄到引用對(duì)象的region對(duì)應(yīng)的remembered set中。當(dāng)進(jìn)行垃圾回收的時(shí)候,在gc roots集中加入region的remembered set,就可以保證就算不全局掃描,也不會(huì)有遺漏。
對(duì)于引用類型的復(fù)制語(yǔ)句,比如 person.t = teacher,假設(shè)新生代對(duì)象: person是分配在region A,然后老年代對(duì)象teacher分配在region B。那么此時(shí)就存在跨代引用。在進(jìn)行賦值之前會(huì)產(chǎn)生write barrier ,會(huì)寫入到dirty card queue中,當(dāng)這個(gè)queue達(dá)到一定值或者時(shí)年輕代要執(zhí)行垃圾回收時(shí),對(duì)card queue中的卡表索引進(jìn)行處理,進(jìn)行更新remembered set保證remembered set實(shí)時(shí)準(zhǔn)確。
這里網(wǎng)上很多資料都說(shuō)引入了卡表(byte[]數(shù)組,CMS中有用到)或者Rset(在卡表結(jié)構(gòu)上實(shí)現(xiàn)的一種hash結(jié)構(gòu),G1采用的一種結(jié)構(gòu))結(jié)構(gòu),在進(jìn)行young gc解決跨代引用問題時(shí),可以避免對(duì)整個(gè)堆進(jìn)行掃描。其實(shí)我們知道并沒有哪一種垃圾回收器會(huì)掃描整個(gè)堆,都只是從GC Roots集合中出發(fā),標(biāo)記存活對(duì)象而已。
回收步驟:
1、初始標(biāo)記:僅僅是比較一下GC Roots能直接關(guān)聯(lián)的對(duì)象,并且修改
TAMS指針的值,讓下一階段用戶線程并發(fā)運(yùn)行的時(shí)候,能正確在可用的
region中分配新對(duì)象。這個(gè)階段需要stop the world,但是停頓很小。
2、并發(fā)標(biāo)記:從GC Root出發(fā),掃描堆,找到要回收的對(duì)象,這個(gè)階段耗時(shí)比較長(zhǎng),但是可以和用戶程序并發(fā)執(zhí)行。當(dāng)對(duì)象掃描完成以后,還要重新處理SATB記錄下的并發(fā)時(shí)有引用變化的對(duì)象。
3、最終標(biāo)記:對(duì)用戶線程做另外一個(gè)短暫的暫停,用于處理并發(fā)階段結(jié)束后能遺留下來(lái)的少量SATB記錄。
4、篩選回收:負(fù)責(zé)更新region的統(tǒng)計(jì)數(shù)據(jù)。
三色標(biāo)記算法:
三色標(biāo)記算法,是將對(duì)象分成三種類型,黑色,灰色和白色。
黑色:根對(duì)象,或者是該對(duì)象被標(biāo)記過(guò)了,同時(shí)它的所有屬性也被標(biāo)記完了。
灰色:本身對(duì)象被標(biāo)記了,但是屬性還有沒被標(biāo)記的。
白色: 未被標(biāo)記的,當(dāng)所有的掃描都完成后,白色的對(duì)象就是不可達(dá)的對(duì)象,也就是垃圾對(duì)象。
并發(fā)標(biāo)記過(guò)程三色標(biāo)記算法:1、開始時(shí),將根節(jié)點(diǎn)的子對(duì)象標(biāo)記為灰色。



SATB算法:在開始標(biāo)記的時(shí)候,會(huì)生成一個(gè)存活對(duì)象的快照,在并發(fā)標(biāo)記的過(guò)程中,所有引用改變的對(duì)象,都入隊(duì)(在產(chǎn)生寫屏障的時(shí)候,將舊引用指向的對(duì)象置為非白的)這種方式可能會(huì)存在浮動(dòng)垃圾(內(nèi)存泄漏),將在下一次進(jìn)行回收。
參考文獻(xiàn):https://plumbr.io/handbook/garbage-collection-algorithms-implementations#g1https://www.infoq.com/articles/tuning-tips-G1-GC/https://tech.meituan.com/2016/09/23/g1.html