G1垃圾回收器詳解

在前一篇的文章《HotSpot垃圾回收算法概述》里面仰税,對于Serial, Parallel和CMS幾種垃圾回收器做了比較詳細(xì)的描述硫眯。但是對于G1的敘述是比較粗糙的疲陕。這篇文章則是提供了G1垃圾回收器的詳細(xì)分析补君。

概述

G1垃圾回收器是在Java7 update 4之后引入的一個新的垃圾回收器。G1是一個分代的芭毙,增量的筋蓖,并行與并發(fā)的標(biāo)記-復(fù)制垃圾回收器。它的設(shè)計(jì)目標(biāo)是為了適應(yīng)現(xiàn)在不斷擴(kuò)大的內(nèi)存和不斷增加的處理器數(shù)量稿蹲,進(jìn)一步降低暫停時間(pause time)扭勉,同時兼顧良好的吞吐量。G1回收器和CMS比起來苛聘,有以下不同:

  1. G1垃圾回收器是compacting的涂炎,因此其回收得到的空間是連續(xù)的。這避免了CMS回收器因?yàn)椴贿B續(xù)空間所造成的問題设哗。如需要更大的堆空間唱捣,更多的floating garbage。連續(xù)空間意味著G1垃圾回收器可以不必采用空閑鏈表的內(nèi)存分配方式网梢,而可以直接采用bump-the-pointer的方式震缭;
  2. G1回收器的內(nèi)存與CMS回收器要求的內(nèi)存模型有極大的不同。G1將內(nèi)存劃分一個個固定大小的region战虏,每個region可以是年輕代拣宰、老年代的一個。內(nèi)存的回收是以region作為基本單位的烦感;

G1還有一個及其重要的特性:軟實(shí)時(soft real-time)巡社。所謂的實(shí)時垃圾回收,是指在要求的時間內(nèi)完成垃圾回收手趣∩胃茫“軟實(shí)時”則是指,用戶可以指定垃圾回收時間的限時绿渣,G1會努力在這個時限內(nèi)完成垃圾回收朝群,但是G1并不擔(dān)保每次都能在這個時限內(nèi)完成垃圾回收。通過設(shè)定一個合理的目標(biāo)中符,可以讓達(dá)到90%以上的垃圾回收時間都在這個時限內(nèi)姜胖。

數(shù)據(jù)結(jié)構(gòu)

在了解G1垃圾回收器的算法前,先熟悉在G1中使用的一些數(shù)據(jù)結(jié)構(gòu)和概念是有用的淀散。如果只是想大概了解一下G1垃圾回收器谭期,那么此節(jié)可以跳過。即便想詳細(xì)了解G1回收器的細(xì)節(jié)也可以先跳過這一節(jié)吧凉,直接閱讀下面的算法詳解隧出,遇到了不明白的數(shù)據(jù)結(jié)構(gòu)和概念,再回來此處尋找解釋阀捅。

G1垃圾回收器的復(fù)雜難懂胀瞪,有很大一部分原因是因?yàn)檫@些數(shù)據(jù)結(jié)構(gòu)。

Heap Region

本質(zhì)上來說,G1垃圾回收器依然是一個分代垃圾回收器凄诞。但是它與一般的回收器所不同的是圆雁,它引入了額外的概念,Region帆谍。G1垃圾回收器把堆劃分成一個個大小相同的Region伪朽。在HotSpot的實(shí)現(xiàn)中,整個堆被劃分成2048左右個Region汛蝙。每個Region的大小在1-32MB之間烈涮,具體多大取決于堆的大小。

G1垃圾回收器的分代也是建立在這些Region的基礎(chǔ)上的窖剑。對于Region來說坚洽,它會有一個分代的類型,并且是唯一一個西土。即讶舰,每一個Region,它要么是young的需了,要么是old的跳昼。還有一類十分特殊的Humongous。所謂的Humongous肋乍,就是一個對象的大小超過了某一個閾值——HotSpot中是Region的1/2鹅颊,那么它會被標(biāo)記為Humongous。如果我們審視HotSpot的其余的垃圾回收器住拭,可以發(fā)現(xiàn)這種對象以前被稱為大對象挪略,會被直接分配老年代历帚。而在G1回收器中滔岳,則是做了特殊的處理。
G1并不要求相同類型的region要相鄰挽牢。換言之谱煤,就是G1回收器不要求它們連續(xù)。當(dāng)然在邏輯上禽拔,分代依舊是連續(xù)的刘离。因此,一種典型的分配可能是:

G1 Regions

注:圖片來自G1: One Garbage Collector To Rule Them All

其中E代表的是Eden睹栖,S代表的是Survivor硫惕,H代表的是Humongous,剩余的深藍(lán)色代表的是Old(或者Tenured)野来,灰色的代表的是空閑的region恼除。
每一個分配的Region,都可以分成兩個部分,已分配的和未被分配的豁辉。它們之間的界限被稱為top令野。總體上來說徽级,把一個對象分配到Region內(nèi)气破,只需要簡單增加top的值。這個做法實(shí)際上就是bump-the-pointer餐抢。過程如下:

Region內(nèi)存分配

Region可以說是G1回收器一次回收的最小單元现使。即每一次回收都是回收N個Region。這個N是多少弹澎,主要受到G1回收的效率和用戶設(shè)置的軟實(shí)時目標(biāo)有關(guān)朴下。每一次的回收,G1會選擇可能回收最多垃圾的Region進(jìn)行回收苦蒿。與此同時殴胧,G1回收器會維護(hù)一個空間Region的鏈表。每次回收之后的Region都會被加入到這個鏈表中佩迟。
每一次都只有一個Region處于被分配的狀態(tài)中团滥,被稱為current region。在多線程的情況下报强,這會帶來并發(fā)的問題灸姊。G1回收器采用和CMS一樣的TLABs的手段。即為每一個線程分配一個Buffer秉溉,線程分配內(nèi)存就在這個Buffer內(nèi)分配力惯。但是當(dāng)線程耗盡了自己的Buffer之后,需要申請新的Buffer召嘶。這個時候依然會帶來并發(fā)的問題父晶。G1回收器采用的是CAS(Compate And Swap)操作。

為線程分配Buffer的過程大概是:

  1. 記錄top值弄跌;
  2. 準(zhǔn)備分配甲喝;
  3. 比較記錄的top值和現(xiàn)在的top值,如果一樣铛只,則執(zhí)行分配埠胖,并且更新top的值;否則淳玩,重復(fù)1直撤;

顯然的,采用TLABs的技術(shù)蜕着,就會帶來碎片谋竖。舉例來說,當(dāng)一個線程在自己的Buffer里面分配的時候,雖然Buffer里面還有剩余的空間圈盔,但是卻因?yàn)榉峙涞膶ο筮^大以至于這些空閑空間無法容納豹芯,此時線程只能去申請新的Buffer,而原來的Buffer中的空閑空間就被浪費(fèi)了驱敲。Buffer的大小和線程數(shù)量都會影響這些碎片的多寡铁蹈。

Remember Set和Card Table

RS(Remember Set)是一種抽象概念,用于記錄從非收集部分指向收集部分的指針的集合众眨。
在傳統(tǒng)的分代垃圾回收算法里面握牧,RS(Remember Set)被用來記錄分代之間的指針。在G1回收器里面娩梨,RS被用來記錄從其他Region指向一個Region的指針情況沿腰。因此,一個Region就會有一個RS狈定。這種記錄可以帶來一個極大的好處:在回收一個Region的時候不需要執(zhí)行全堆掃描颂龙,只需要檢查它的RS就可以找到外部引用,而這些引用就是initial mark的根之一纽什。

那么措嵌,如果一個線程修改了Region內(nèi)部的引用,就必須要去通知RS芦缰,更改其中的記錄企巢。為了達(dá)到這種目的,G1回收器引入了一種新的結(jié)構(gòu)让蕾,CT(Card Table)——卡表浪规。每一個Region,又被分成了固定大小的若干張卡(Card)探孝。每一張卡笋婿,都用一個Byte來記錄是否修改過≡俟茫卡表即這些byte的集合萌抵。實(shí)際上找御,如果把RS理解成一個概念模型元镀,那么CT就可以說是RS的一種實(shí)現(xiàn)方式。

從第一感覺霎桅,或者出于直覺的考慮栖疑,使用一個bit來記錄一張卡是否被修改過,就已經(jīng)足夠了滔驶。而使用一個byte會造成更多的空間開銷遇革。但是實(shí)際上,使用一個byte來記錄一張卡是否被修改過,會比使用一個bit來記錄效率更高萝快。更多細(xì)節(jié)參閱資料3锻霎。

在RS的修改上也會遇到并發(fā)的問題。因?yàn)橐粋€Region可能有多個線程在并發(fā)修改揪漩,因此它們也會并發(fā)修改RS旋恼。為了避免這樣一種沖突,G1垃圾回收器進(jìn)一步把RS劃分成了多個哈希表奄容。每一個線程都在各自的哈希表里面修改冰更。最終,從邏輯上來說昂勒,RS就是這些哈希表的集合蜀细。哈希表是實(shí)現(xiàn)RS的一種通常的方式之一。它有一個極大的好處就是能夠去除重復(fù)戈盈。這意味著奠衔,RS的大小將和修改的指針數(shù)量相當(dāng)。而在不去重的情況下塘娶,RS的數(shù)量和寫操作的數(shù)量相當(dāng)涣觉。

整個關(guān)系如下:

Remember Set

圖中RS的虛線表名的是,RS并不是一個和Card Table獨(dú)立的血柳,不同的數(shù)據(jù)結(jié)構(gòu)官册,而是指RS是一個概念模型。實(shí)際上难捌,Card Table是RS的一種實(shí)現(xiàn)方式膝宁。

Remember Set的寫屏障

寫屏障是指,在改變特定內(nèi)存的值(實(shí)際上也就是寫入內(nèi)存)的時候額外執(zhí)行的一些動作根吁。在大多數(shù)的垃圾回收算法中员淫,都利用到了寫屏障。寫屏障通常用于在運(yùn)行時探測并記錄回收相關(guān)指針(interesting pointer)击敌,在回收器只回收堆中部分區(qū)域的時候介返,任何來自該區(qū)域外的指針都需要被寫屏障捕獲,這些指針將會在垃圾回收的時候作為標(biāo)記開始的根沃斤。JAVA使用的其余的分代的垃圾回收器圣蝎,都有寫屏障。舉例來說衡瓶,每一次將一個老年代對象的引用修改為指向年輕代對象徘公,都會被寫屏障捕獲,并且記錄下來哮针。因此在年輕代回收的時候关面,就可以避免掃描整個老年代來查找根坦袍。

G1垃圾回收器的寫屏障和RS是相輔相成的,也就是記錄Region內(nèi)部的指針等太。這種記錄發(fā)生在寫操作之后捂齐。對于一個寫屏障來說,過濾掉不必要的寫操作是十分有必要的缩抡。這種過濾既能加快賦值器的速度辛燥,也能減輕回收器的負(fù)擔(dān)。G1垃圾回收器采用的雙重過濾

  1. 過濾掉同一個Region內(nèi)部引用缝其;
  2. 過濾掉空引用挎塌;

過濾掉這兩個部分之后,可以使RS的大小大大減小内边。

G1的垃圾回收器的寫屏障使用一種兩級的log buffer結(jié)構(gòu):

  1. global set of filled buffer:所有線程共享的一個全局的榴都,存放填滿了的log buffer的集合;
  2. thread log buffer:每個線程自己的log buffer漠其。所有的線程都會把寫屏障的記錄先放進(jìn)去自己的log buffer中嘴高,裝滿了之后,就會把log buffer放到 global set of filled buffer中和屎,而后再申請一個log buffer拴驮;

可以內(nèi)容可以參閱資料4的11.8節(jié)

Collect Set

Collect Set(CSet)是指,在Evacuation階段柴信,由G1垃圾回收器選擇的待回收的Region集合套啤。G1垃圾回收器的軟實(shí)時的特性就是通過CSet的選擇來實(shí)現(xiàn)的。對應(yīng)于算法的兩種模式fully-young generational mode和partially-young mode随常,CSet的選擇可以分成兩種:

  1. 在fully-young generational mode下:顧名思義潜沦,該模式下CSet將只包含young的Region。G1將調(diào)整young的Region的數(shù)量來匹配軟實(shí)時的目標(biāo)绪氛;
  2. 在partially-young mode下:該模式會選擇所有的young region唆鸡,并且選擇一部分的old region。old region的選擇將依據(jù)在Marking cycle phase中對存活對象的計(jì)數(shù)枣察。G1選擇存活對象最少的Region進(jìn)行回收争占。

SATB(snapshot-at-the-beginning)

SATB(snapshot-at-the-beginning),是最開始用于實(shí)時垃圾回收器的一種技術(shù)序目。G1垃圾回收器使用該技術(shù)在標(biāo)記階段記錄一個存活對象的快照("logically takes a snapshot of the set of live objects in the heap at the start of marking cycle")臂痕。然而在并發(fā)標(biāo)記階段,應(yīng)用可能修改了原本的引用宛琅,比如刪除了一個原本的引用刻蟹。這就會導(dǎo)致并發(fā)標(biāo)記結(jié)束之后的存活對象的快照和SATB不一致逗旁。G1是通過在并發(fā)標(biāo)記階段引入一個寫屏障來解決這個問題的:每當(dāng)存在引用更新的情況嘿辟,G1會將修改之前的值寫入一個log buffer(這個記錄會過濾掉原本是空引用的情況)舆瘪,在最終標(biāo)記(final marking phase)階段掃描SATB,修正SATB的誤差红伦。

SATB的log buffer如RS的寫屏障使用的log buffer一樣英古,都是兩級結(jié)構(gòu),作用機(jī)制也是一樣的昙读。

細(xì)節(jié)可以參閱資料2召调,6

Marking bitmaps和TAMS

Marking bitmap是一種數(shù)據(jù)結(jié)構(gòu),其中的每一個bit代表的是一個可用于分配給對象的起始地址蛮浑。舉例來說:

bitmap

其中addrN代表的是一個對象的起始地址唠叛。綠色的塊代表的是在該起始地址處的對象是存活對象,而其余白色的塊則代表了垃圾對象沮稚。
G1使用了兩個bitmap艺沼,一個叫做previous bitmap,另外一個叫做next bitmap蕴掏。previous bitmap記錄的是上一次的標(biāo)記階段完成之后的構(gòu)造的bitmap障般;next bitmap則是當(dāng)前正在標(biāo)記階段正在構(gòu)造的bitmap。在當(dāng)前標(biāo)記階段結(jié)束之后盛杰,當(dāng)前標(biāo)記的next bitmap就變成了下一次標(biāo)記階段的previous bitmap挽荡。
TAMS(top at mark start)變量,是一對用于區(qū)分在標(biāo)記階段新分配對象的變量即供,分別被稱為previous TAMS和next TAMS定拟。在previous TAMS和next TAMS之間的對象則是本次標(biāo)記階段時候新分配的對象。如圖:

previous TMAS 和 next TAMS

白色region代表的是空閑空間逗嫡,綠色region代表是存活對象办素,橙色region代表的在此次標(biāo)記階段新分配的對象。注意的是祸穷,在橙色區(qū)域的對象性穿,并不能確保它們都事實(shí)上是存活的。

算法詳解

整個算法可以分成兩大部分:

  1. Marking cycle phase:標(biāo)記階段雷滚,該階段是不斷循環(huán)進(jìn)行的需曾;
  2. Evacuation phase:該階段是負(fù)責(zé)把一部分region的活對象拷貝到空Region里面去,然后回收原本的Region空間祈远,該階段是STW(stop-the-world)的呆万;

而算法也可以分成兩種模式:

  1. fully-young generational mode:有時候也會被稱為young GC,該模式只會回收young region车份,算法是通過調(diào)整young region的數(shù)量來達(dá)到軟實(shí)時目標(biāo)的谋减;
  2. partially-young mode:也被稱為Mixed GC,該階段會回收young region和old region扫沼,算法通過調(diào)整old region的數(shù)量來達(dá)到軟實(shí)時目標(biāo)出爹;

有趣的地方是不論處在何種模式之下庄吼,yong region都在被回收的范圍內(nèi)。而old region只能期望于Mixed GC严就。但是图甜,如同在CMS垃圾回收器中遇到的困境一樣次员,Mixed GC可能來不及回收old region。也就說,在需要分配老年代的對象的時候潮秘,并沒有足夠的空間跺撼。這個時候就只能觸發(fā)一次full GC灭贷。

算法會自動在young GC和mixed GC之間切換削茁,并且定期觸發(fā)Marking cycle phase。HotSpot的G1實(shí)現(xiàn)允許指定一個參數(shù)InitiatingHeapOccupancyPercent粟害,在達(dá)到該參數(shù)的情況下旁理,就會執(zhí)行marking cycle phase。

算法并不使用在對象頭增加字段來標(biāo)記該對象我磁,而是采用bitmap的方式來記錄一個對象被標(biāo)記的情況孽文。這種記錄方法的好處就是在使用這些標(biāo)記信息的時候,僅僅需要掃描bitmap而已夺艰。G1統(tǒng)計(jì)一個region的存活的對象芋哭,就是依賴于bitmap的標(biāo)記。

Marking Cycle Phase

算法的Marking cycle phase大概可以分成五個階段:

  1. Initial marking phase:G1收集器掃描所有的根郁副。該過程是和young GC的暫停過程一起的减牺;
  2. Root region scanning phase:掃描Survivor Regions中指向老年代的被initial mark phase標(biāo)記的引用及引用的對象,這一個過程是并發(fā)進(jìn)行的存谎。但是該過程要在下一個young GC開始之前結(jié)束拔疚;
  3. Concurrent marking phase:并發(fā)標(biāo)記階段,標(biāo)記整個堆的存活對象既荚。該過程可以被young GC所打斷稚失。并發(fā)階段產(chǎn)生的新的引用(或者引用的更新)會被SATB的write barrier記錄下來;
  4. Remark phase:也叫final marking phase恰聘。該階段只需要掃描SATB(Snapshot At The Beginning)的buffer句各,處理在并發(fā)階段產(chǎn)生的新的存活對象的引用。作為對比晴叨,CMS的remark需要掃描整個mod union table的標(biāo)記為dirty的entry以及全部根凿宾;
  5. Cleanup phase:清理階段。該階段會計(jì)算每一個region里面存活的對象兼蕊,并把完全沒有存活對象的Region直接放到空閑列表中初厚。在該階段還會重置Remember Set。該階段在計(jì)算Region中存活對象的時候孙技,是STW(Stop-the-world)的产禾,而在重置Remember Set的時候排作,卻是可以并行的;

Initial marking phase

該階段掃描所有的根下愈,與CMS類似纽绍。所不同的是蕾久,該階段是和young GC一起的势似。這里的young GC實(shí)際上是指的就是fully-young generational mode。

Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Guide的原文是"This phase is piggybacked on a normal (STW) young garbage collection"僧著。

Root region scanning phase

該過程主要是掃描Survivor region中指向老年代的履因,在initial mark phase標(biāo)記的引用及其引用的對象。這是一個很奇怪的步驟盹愚,因?yàn)樵谇懊娌徽撌荘arallel Collector還是CMS栅迄,都沒有這么一個步驟。

要理解這一點(diǎn)皆怕,要注意的是毅舆,算法的兩種模式,不論是young GC還是mixed GC愈腾,都需要回收young region憋活。因?yàn)閷?shí)際上RS是不記錄從young region出發(fā)的指針,例如虱黄,這部分指針包括young region - young region悦即,也包括young-region - old region指針。那么就可能出現(xiàn)一種情況橱乱,一個老年代的存活對象辜梳,只被年輕代的對象引用。在一次young GC中泳叠,這些存活的年輕代的對象會被復(fù)制到Survivor Region作瞄,因此需要掃描這些Survivor region來查找這些指向老年代的對象的引用,作為并發(fā)標(biāo)記階段掃描老年代的根的一部分危纫。

在理解了這一點(diǎn)的基礎(chǔ)上粉洼,那么對于階段必須在下一次young GC啟動前完成的要求,也就理解了叶摄。因?yàn)槿绻诙蔚膟oung GC啟動了属韧,那么這個過程中,survivor region就可能發(fā)生變化蛤吓。這個時候執(zhí)行root region phase就會產(chǎn)生錯誤的結(jié)果宵喂。

Concurrent marking phase

在標(biāo)記階段,會使用到一個marking stack的東西会傲。G1不斷從marking stack中取出引用锅棕,遞歸掃描整個堆里的對象圖拙泽,并且在bitmap上進(jìn)行標(biāo)記。這個遞歸過程采用的是深度遍歷裸燎,會不斷把對象的域入棧顾瞻。

在并發(fā)標(biāo)記階段,因?yàn)閼?yīng)用還在運(yùn)行德绿,所以可能會有引用變更荷荤,包括現(xiàn)有引用指向別的對象,或者刪除了一個引用移稳,或者創(chuàng)建了一個新的對象等蕴纳。G1采用的是使用SATB的并發(fā)標(biāo)記算法。

在資料6中記錄了使用SATB的兩條原則:

  1. All accessible cells at the beginning of the garbage collection are eventually marked during the marked phase;
  2. Newly alocated cells during the garbage collection are never collected during the sweep phase of that garbage collection

在G1中个粱,該算法的關(guān)鍵在于古毛,如果在并發(fā)標(biāo)記的時候,出現(xiàn)了引用修改(不包含新分配內(nèi)存給對象)都许,那么寫屏障會把這些引用的原始值捕獲下來稻薇,記錄在log buffer中。而后再處理胶征。后續(xù)的所有的標(biāo)記塞椎,都是從原來的值出發(fā),而不是從新的值出發(fā)的弧烤。

SATB是一個邏輯上存在概念忱屑,在實(shí)際中并沒有任何真的實(shí)際的數(shù)據(jù)結(jié)構(gòu)與之對應(yīng)。叫這個名字暇昂,是因?yàn)檩航洌坏┻M(jìn)入了concurrent marking階段,那么該在該階段的運(yùn)行過程中急波,即便應(yīng)用修改了引用从铲,但是因?yàn)镾ATB的寫屏障記錄下來了原始的值,在遍歷整個堆查找存活對象的時候澄暮,使用的依然是原來的值名段。這就是在邏輯上保持了一個snapshot at the beginning of concurrent marking phase。

在處理新創(chuàng)建的對象泣懊,G1采用了不同的方式伸辟。G1用了兩個TAMS變量了判斷新創(chuàng)建的對象。一個叫做previous TAMS馍刮,一個叫做next TAMS信夫。位于兩者之間的對象就是新分配的對象。

并發(fā)標(biāo)記階段,bitmap和TAMS的作用如圖:

bitmap和TAMS的作用

注:圖片引自資料2

該圖的詳細(xì)解釋如下:

  1. A是第一次marking cycle的initial marking階段静稻。next bitmap尚未標(biāo)記任何存活對象警没,而此時的previous TAMS被初始化為region內(nèi)存地址起始值,next TAMS被初始化為top振湾。top實(shí)際上就是一個region未分配區(qū)域和已分配區(qū)域的分界點(diǎn)杀迹;
  2. B是經(jīng)過concurrent marking階段之后,進(jìn)入了remark階段押搪。此時存活對象的掃描已經(jīng)完成了树酪,因此next bitmap構(gòu)造好了,剛好代表的是當(dāng)下狀態(tài)中region中的內(nèi)存使用情況嵌言。注意的是嗅回,此時top已經(jīng)不再與next TAMS重合了及穗,top和next TAMS之間的就是在前面標(biāo)記階段之時摧茴,新分配的對象;
  3. C代表的是clean up階段埂陆。C和B比起來苛白,next bitmap變成了previous bitmap,而在bitmap中標(biāo)記為垃圾(也就是白色區(qū)域的)的對應(yīng)的region的區(qū)域也被染成了淺灰色焚虱。這并不是指垃圾對象已經(jīng)被清掃了购裙,僅僅是標(biāo)記出來了。同時next TAMS和previous TAMS也交換了角色鹃栽;
  4. D代表的是下一個marking cycle的initial marking階段躏率,該階段和A類似,next TAMS重新被初始化為top的值民鼓;
  5. EF就是BC的重復(fù)薇芝;

Remark phase

該階段是一個STW的階段。引入該階段的目的丰嘉,是為了能夠達(dá)到結(jié)束標(biāo)記的目標(biāo)夯到。要結(jié)束標(biāo)記的過程,要滿足三個條件:

  1. concurrent marking已經(jīng)追蹤了所有的存活對象饮亏;
  2. marking stack是空的耍贾;
  3. 所有的log都被處理了;

前兩個條件是很容易達(dá)到的路幸,但是最后一個是很困難的荐开。如果不引入一個STW的remark過程,那么應(yīng)用會不斷的更新引用简肴,也就是說晃听,會不斷的產(chǎn)生log,因而永遠(yuǎn)也無法達(dá)成完成標(biāo)記的條件。

Clean up

該階段主要完成:

  1. 統(tǒng)計(jì)存活對象杂伟,這是利用RS和bitmap來完成的移层,統(tǒng)計(jì)的結(jié)果將會用來排序region,以用于下一次的CSet的選擇赫粥;
  2. 重置RSet观话;
  3. 把空閑region放到空閑region列表中;

該階段比較容易引起誤解地方在于越平,Clean up并不會清理垃圾對象频蛔,也不會執(zhí)行存活對象的拷貝。也就是說秦叛,在極端情況下晦溪,該階段結(jié)束之后,空閑Region列表將毫無變化挣跋,JVM的內(nèi)存使用情況也毫無變化三圆。

Evacuation

Evacuation階段STW的,大概可以分成兩個步驟:第一個步驟是從Region中選出若干個Region進(jìn)行回收避咆,這些被選中的Region稱為Collect Set(簡稱CSet)舟肉;而第二個步驟則是把這些Region中存活的對象復(fù)制到空閑的Region中去,同時把這些已經(jīng)被回收的Region放到空閑Region列表中查库。
這兩個步驟又可以被分解成三個任務(wù):

  1. 根據(jù)RS的日志更新RS:只有在處理完了RS的日志之后路媚,RS才能夠保證是準(zhǔn)確的,完整的樊销,這也是Evacuation是STW的重要原因整慎;
  2. 掃描RS和其余的根來確定存活對象:該階段實(shí)際上最主要依賴于RS;
  3. 拷貝存活對象:該階段只要從2中確定的根觸發(fā)围苫,沿著引用鏈一直追溯下去裤园,將存活對象復(fù)制到新的region就可以。這個過程中够吩,可能有一部分的年輕代對象會被提升到老年代比然;

Evacuation的時機(jī)

Evacuation的觸發(fā)時機(jī)在不同的模式下會有一些不同。在不同的模式下都相同的是周循,只要堆的使用率達(dá)到了某個閾值强法,就必然會觸發(fā)Evacuation。這是為了確保在Evacuation的時候有足夠的空閑Region來容納存活對象湾笛。

在young GC的情況下饮怯,G1會選擇N個region作為CSet,該CSet首先需要滿足軟實(shí)時的要求嚎研,而一旦已經(jīng)有N個region已經(jīng)被分配了蓖墅,那么就會執(zhí)行一次Evacuation库倘。

G1會盡可能的執(zhí)行mixed GC。唯一的限制就是mix GC也需要滿足軟實(shí)時的要求论矾。

G1觸發(fā)Evacuation的原則大概是:

  1. 如果被分配的young region數(shù)量滿足young GC的要求教翩,那么就會觸發(fā)young GC;
  2. 如果被分配的young region數(shù)量不滿足young GC贪壳,就會進(jìn)一步考察加上old region的數(shù)量饱亿,能否滿足old GC的要求;

為了理解這一點(diǎn)闰靴,可以舉例來說彪笼,假如回收一個old region的時間是回收一個young region的兩倍,也就是young region花費(fèi)時間T蚂且,old region花費(fèi)2T配猫,在滿足軟實(shí)時目標(biāo)的情況下,GC只能回收8T的region杏死,那么:

  1. 假如應(yīng)用現(xiàn)在只分配k(k<8)塊young region泵肄,沒有分配任何old region。這個時候又分配了一個old region识埋,那么這個時候會立刻觸發(fā)一次mixed GC凡伊,此次GC會選擇k塊young region和一塊old region零渐;
  2. 因此窒舟,在這種假設(shè)下,只要有可以回收的old region的時候诵盼,總是會先回收old region惠豺;
  3. 在沒有任何old region的情況下,才有可能觸發(fā)young region风宁。

當(dāng)然洁墙,在一般情況下,這些假設(shè)是不成立的戒财。讀者可以思考一下热监,在young GC和mixed GC達(dá)到軟實(shí)時的要求下,young region和old region之間回收的花銷不同會導(dǎo)致young GC和mixed GC會在什么情況下觸發(fā)饮寞。

資料

  1. Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide
  2. David Detlefs, Christine Flood, Steve Heller, Tony Printezis. Garbage-First Garbage Collection
  3. Urs Ho?lzle. A Fast Write Barrier for Generational Collectors
  4. 垃圾回收算法手冊——自動內(nèi)存管理的藝術(shù)
  5. 請教G1算法的原理——RednaxelaFX的回答
  6. Taichi Yuasa. Real-time garbage collection on general-purpose machines.
  7. Christine H. Flood, David Detlefs, Nir Shavit, and Xiaolan Zhang. Parallel garbage collection for shared memory multiprocessors
  8. 名詞連接貼-RednaxelaFX對Remeber Set和Card Table的解釋
  9. G1: One Garbage Collector To Rule Them All
  10. Poonam Parhar. Understanding G1 GC Logs
  11. Getting Started with the G1 Garbage Collector
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末孝扛,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子幽崩,更是在濱河造成了極大的恐慌苦始,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慌申,死亡現(xiàn)場離奇詭異陌选,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門咨油,熙熙樓的掌柜王于貴愁眉苦臉地迎上來您炉,“玉大人,你說我怎么就攤上這事役电×诳裕” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵宴霸,是天一觀的道長囱晴。 經(jīng)常有香客問我,道長瓢谢,這世上最難降的妖魔是什么畸写? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮氓扛,結(jié)果婚禮上枯芬,老公的妹妹穿的比我還像新娘。我一直安慰自己采郎,他們只是感情好千所,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蒜埋,像睡著了一般淫痰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上整份,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天待错,我揣著相機(jī)與錄音,去河邊找鬼烈评。 笑死火俄,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的讲冠。 我是一名探鬼主播瓜客,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼竿开!你這毒婦竟也來了谱仪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤德迹,失蹤者是張志新(化名)和其女友劉穎芽卿,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胳搞,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡卸例,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年称杨,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筷转。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡姑原,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呜舒,到底是詐尸還是另有隱情锭汛,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布袭蝗,位于F島的核電站唤殴,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏到腥。R本人自食惡果不足惜朵逝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乡范。 院中可真熱鬧配名,春花似錦、人聲如沸晋辆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓶佳。三九已至芋膘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涩哟,已是汗流浹背索赏。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贴彼,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓埃儿,卻偏偏與公主長得像器仗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子童番,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容