G1從入門到放棄(一)

G1從入門到放棄(一)

最近在看關(guān)于G1垃圾收集的文章,看了很多國(guó)內(nèi)與國(guó)外的資料,本文對(duì)G1的這些資料進(jìn)行了整理。這篇合適JVM垃圾回收有一定基礎(chǔ)的同學(xué)时鸵,作為G1入門可以看一下,如果要死磕G1實(shí)現(xiàn)的內(nèi)容細(xì)節(jié)厅瞎。大家可以找R大饰潜。 個(gè)人認(rèn)為R大是目前國(guó)內(nèi)JVM領(lǐng)域研究的先驅(qū)了,當(dāng)然R大也是不建議大家去看JVM的源碼的和簸。為啥別讀HotSpot VM的源碼
G1系列第一篇文章會(huì)介紹G1的理論知識(shí)彭雾,不會(huì)做JVM源碼的深入分析。第二篇準(zhǔn)備介紹G1實(shí)踐中的日志分析锁保。

為什么要學(xué)G1

G1(Garbadge First Collector)作為一款JVM最新的垃圾收集器薯酝,可以解決CMS中Concurrent Mode Failed問題,盡量縮短處理超大堆的停頓身诺,在G1進(jìn)行垃圾回收的時(shí)候完成內(nèi)存壓縮蜜托,降低內(nèi)存碎片的生成抄囚。G1在堆內(nèi)存比較大的時(shí)候表現(xiàn)出比較高吞吐量和短暫的停頓時(shí)間霉赡,而且已成為Java 9的默認(rèn)收集器。未來(lái)替代CMS只是時(shí)間的問題幔托。

G1的GC原理

Region

G1的內(nèi)存結(jié)構(gòu)和傳統(tǒng)的內(nèi)存空間劃分有比較的不同穴亏。G1將內(nèi)存劃分成了多個(gè)大小相等的Region(默認(rèn)是512K),Region邏輯上連續(xù)重挑,物理內(nèi)存地址不連續(xù)嗓化。同時(shí)每個(gè)Region被標(biāo)記成E、S谬哀、O刺覆、H,分別表示Eden史煎、Survivor谦屑、Old、Humongous篇梭。其中E氢橙、S屬于年輕代,O與H屬于老年代恬偷。
示意圖如下:


image.png

H表示Humongous悍手。從字面上就可以理解表示大的對(duì)象(下面簡(jiǎn)稱H對(duì)象)。當(dāng)分配的對(duì)象大于等于Region大小的一半的時(shí)候就會(huì)被認(rèn)為是巨型對(duì)象。H對(duì)象默認(rèn)分配在老年代坦康,可以防止GC的時(shí)候大對(duì)象的內(nèi)存拷貝竣付。通過如果發(fā)現(xiàn)堆內(nèi)存容不下H對(duì)象的時(shí)候,會(huì)觸發(fā)一次GC操作滞欠。

跨代引用

在進(jìn)行Young GC的時(shí)候卑笨,Young區(qū)的對(duì)象可能還存在Old區(qū)的引用, 這就是跨代引用的問題仑撞。為了解決Young GC的時(shí)候赤兴,掃描整個(gè)老年代,G1引入了Card TableRemember Set的概念隧哮,基本思想就是用空間換時(shí)間桶良。這兩個(gè)數(shù)據(jù)結(jié)構(gòu)是專門用來(lái)處理Old區(qū)到Y(jié)oung區(qū)的引用。Young區(qū)到Old區(qū)的引用則不需要單獨(dú)處理沮翔,因?yàn)閅oung區(qū)中的對(duì)象本身變化比較大陨帆,沒必要浪費(fèi)空間去記錄下來(lái)。

  • RSet:全稱Remembered Sets, 用來(lái)記錄外部指向本Region的所有引用采蚀,每個(gè)Region維護(hù)一個(gè)RSet疲牵。
  • Card: JVM將內(nèi)存劃分成了固定大小的Card。這里可以類比物理內(nèi)存上page的概念榆鼠。

下圖展示的是RSetCard的關(guān)系纲爸。每個(gè)Region被分成了多個(gè)Card,其中綠色部分的Card表示該Card中有對(duì)象引用了其他Card中的對(duì)象妆够,這種引用關(guān)系用藍(lán)色實(shí)線表示识啦。RSet其實(shí)是一個(gè)HashTable,Key是Region的起始地址神妹,Value是Card Table (字節(jié)數(shù)組),字節(jié)數(shù)組下標(biāo)表示Card的空間地址颓哮,當(dāng)該地址空間被引用的時(shí)候會(huì)被標(biāo)記為dirty_card

image.png

關(guān)于RSet結(jié)構(gòu)的維護(hù)鸵荠,可以參考這篇文章冕茅,這里不做過多的深入。

SATB

SATB的全稱(Snapshot At The Beginning)字面意思是開始GC前存活對(duì)象的一個(gè)快照蛹找。SATB的作用是保證在并發(fā)標(biāo)記階段的正確性姨伤。如何理解這句話?
首先要介紹三色標(biāo)記算法熄赡。


image.png
  • 黑色:根對(duì)象姜挺,或者該對(duì)象與它的子對(duì)象都被掃描
  • 灰色:對(duì)象本身被掃描,但還沒掃描完該對(duì)象中的子對(duì)象
  • 白色:未被掃描對(duì)象,掃描完成所有對(duì)象之后彼硫,最終為白色的為不可達(dá)對(duì)象炊豪,即垃圾對(duì)象凌箕。

在GC掃描C之前的顏色如下:


image.png

在并發(fā)標(biāo)記階段,應(yīng)用線程改變了這種引用關(guān)系

A.c=C
B.c=null

得到如下結(jié)果词渤。


image.png

在重新標(biāo)記階段掃描結(jié)果如下


image.png

這種情況下C會(huì)被當(dāng)做垃圾進(jìn)行回收牵舱。Snapshot的存活對(duì)象原來(lái)是A、B缺虐、C芜壁,現(xiàn)在變成A、B了高氮,Snapshot的完整遭到破壞了慧妄,顯然這個(gè)做法是不合理。
G1采用的是pre-write barrier解決這個(gè)問題剪芍。簡(jiǎn)單說就是在并發(fā)標(biāo)記階段塞淹,當(dāng)引用關(guān)系發(fā)生變化的時(shí)候,通過pre-write barrier函數(shù)會(huì)把這種這種變化記錄并保存在一個(gè)隊(duì)列里罪裹,在JVM源碼中這個(gè)隊(duì)列叫satb_mark_queue饱普。在remark階段會(huì)掃描這個(gè)隊(duì)列,通過這種方式状共,舊的引用所指向的對(duì)象就會(huì)被標(biāo)記上套耕,其子孫也會(huì)被遞歸標(biāo)記上,這樣就不會(huì)漏標(biāo)記任何對(duì)象峡继,snapshot的完整性也就得到了保證冯袍。

這里引用R大對(duì)SATB的解釋:

其實(shí)只需要用pre-write barrier把每次引用關(guān)系變化時(shí)舊的引用值記下來(lái)就好了。這樣鬓椭,等concurrent marker到達(dá)某個(gè)對(duì)象時(shí)颠猴,這個(gè)對(duì)象的所有引用類型字段的變化全都有記錄在案关划,就不會(huì)漏掉任何在snapshot里活的對(duì)象小染。當(dāng)然,很可能有對(duì)象在snapshot中是活的贮折,但隨著并發(fā)GC的進(jìn)行它可能本來(lái)已經(jīng)死了裤翩,但SATB還是會(huì)讓它活過這次GC。CMS的incremental update設(shè)計(jì)使得它在remark階段必須重新掃描所有線程棧和整個(gè)young gen作為root调榄;G1的SATB設(shè)計(jì)在remark階段則只需要掃描剩下的satb_mark_queue 踊赠,解決了CMS垃圾收集器重新標(biāo)記階段長(zhǎng)時(shí)間STW的潛在風(fēng)險(xiǎn)。"

SATB的方式記錄活對(duì)象每庆,也就是那一時(shí)刻對(duì)象snapshot, 但是在之后這里面的對(duì)象可能會(huì)變成垃圾, 叫做浮動(dòng)垃圾(floating garbage)筐带,這種對(duì)象只能等到下一次收集回收掉。在GC過程中新分配的對(duì)象都當(dāng)做是活的缤灵,其他不可達(dá)的對(duì)象就是死的伦籍。
如何知道哪些對(duì)象是GC開始之后新分配的呢蓝晒?
在Region中通過top-at-mark-start(TAMS)指針,分別為prevTAMS和nextTAMS來(lái)記錄新配的對(duì)象帖鸦。示意圖如下:

image.png

每個(gè)region記錄著兩個(gè)top-at-mark-start(TAMS)指針芝薇,分別為prevTAMS和nextTAMS。在TAMS以上的對(duì)象就是新分配的作儿,因而被視為隱式marked洛二。 這里引用R大的解釋。

G1的concurrent marking用了兩個(gè)bitmap: 一個(gè)prevBitmap記錄第n-1輪concurrent marking所得的對(duì)象存活狀態(tài)攻锰。由于第n-1輪concurrent marking已經(jīng)完成晾嘶,這個(gè)bitmap的信息可以直接使用。 一個(gè)nextBitmap記錄第n輪concurrent marking的結(jié)果娶吞。這個(gè)bitmap是當(dāng)前將要或正在進(jìn)行的concurrent marking的結(jié)果变擒,尚未完成,所以還不能使用寝志。

其中top是該region的當(dāng)前分配指針娇斑,[bottom, top)是當(dāng)前該region已用(used)的部分,[top, end)是尚未使用的可分配空間(unused)材部。
(1): [bottom, prevTAMS): 這部分里的對(duì)象存活信息可以通過prevBitmap來(lái)得知
(2): [prevTAMS, nextTAMS): 這部分里的對(duì)象在第n-1輪concurrent marking是隱式存活的
(3): [nextTAMS, top): 這部分里的對(duì)象在第n輪concurrent marking是隱式存活的

G1的GC模式

Young GC

Young GC 回收的是所有年輕代的Region毫缆。當(dāng)E區(qū)不能再分配新的對(duì)象時(shí)就會(huì)觸發(fā)。E區(qū)的對(duì)象會(huì)移動(dòng)到S區(qū)乐导,當(dāng)S區(qū)空間不夠的時(shí)候苦丁,E區(qū)的對(duì)象會(huì)直接晉升到O區(qū),同時(shí)S區(qū)的數(shù)據(jù)移動(dòng)到新的S區(qū)物臂,如果S區(qū)的部分對(duì)象到達(dá)一定年齡旺拉,會(huì)晉升到O區(qū)。
Yung GC過程示意圖如下:

image.png

Mixed GC

Mixed GC 翻譯過來(lái)叫混合回收棵磷。之所以叫混合是因?yàn)榛厥账械哪贻p代的Region+部分老年代的Region蛾狗。
1、為什么是老年代的部分Region仪媒?
2沉桌、什么時(shí)候觸發(fā)Mixed GC?
這兩個(gè)問題其實(shí)可以一并回答∷惴裕回收部分老年代是參數(shù)-XX:MaxGCPauseMillis留凭,用來(lái)指定一個(gè)G1收集過程目標(biāo)停頓時(shí)間,默認(rèn)值200ms偎巢,當(dāng)然這只是一個(gè)期望值蔼夜。G1的強(qiáng)大之處在于他有一個(gè)停頓預(yù)測(cè)模型(Pause Prediction Model),他會(huì)有選擇的挑選部分Region压昼,去盡量滿足停頓時(shí)間求冷,關(guān)于G1的這個(gè)模型是如何建立的翠订,這里不做深究。
Mixed GC的觸發(fā)也是由一些參數(shù)控制遵倦。比如XX:InitiatingHeapOccupancyPercent表示老年代占整個(gè)堆大小的百分比尽超,默認(rèn)值是45%,達(dá)到該閾值就會(huì)觸發(fā)一次Mixed GC梧躺。

Mixed GC主要可以分為兩個(gè)階段:
1似谁、全局并發(fā)標(biāo)記(global concurrent marking)
全局并發(fā)標(biāo)記又可以進(jìn)一步細(xì)分成下面幾個(gè)步驟:

  • 初始標(biāo)記(initial mark,STW)掠哥。它標(biāo)記了從GC Root開始直接可達(dá)的對(duì)象巩踏。初始標(biāo)記階段借用young GC的暫停,因而沒有額外的续搀、單獨(dú)的暫停階段塞琼。
  • 并發(fā)標(biāo)記(Concurrent Marking)。這個(gè)階段從GC Root開始對(duì)heap中的對(duì)象標(biāo)記禁舷,標(biāo)記線程與應(yīng)用程序線程并行執(zhí)行彪杉,并且收集各個(gè)Region的存活對(duì)象信息。過程中還會(huì)掃描上文中提到的SATB write barrier所記錄下的引用牵咙。
  • 最終標(biāo)記(Remark派近,STW)。標(biāo)記那些在并發(fā)標(biāo)記階段發(fā)生變化的對(duì)象洁桌,將被回收渴丸。
  • 清除垃圾(Cleanup,部分STW)另凌。這個(gè)階段如果發(fā)現(xiàn)完全沒有活對(duì)象的region就會(huì)將其整體回收到可分配region列表中谱轨。 清除空Region。

2、拷貝存活對(duì)象(Evacuation)
Evacuation階段是全暫停的。它負(fù)責(zé)把一部分region里的活對(duì)象拷貝到空region里去(并行拷貝)荸实,然后回收原本的region的空間。Evacuation階段可以自由選擇任意多個(gè)region來(lái)獨(dú)立收集構(gòu)成收集集合(collection set娜扇,簡(jiǎn)稱CSet),CSet集合中Region的選定依賴于上文中提到的停頓預(yù)測(cè)模型栅组,該階段并不evacuate所有有活對(duì)象的region,只選擇收益高的少量region來(lái)evacuate枢析,這種暫停的開銷就可以(在一定范圍內(nèi))可控玉掸。

Mixed GC的清理過程示意圖如下:


image.png

Full GC

G1的垃圾回收過程是和應(yīng)用程序并發(fā)執(zhí)行的,當(dāng)Mixed GC的速度趕不上應(yīng)用程序申請(qǐng)內(nèi)存的速度的時(shí)候醒叁,Mixed G1就會(huì)降級(jí)到Full GC司浪,使用的是Serial GC泊业。Full GC會(huì)導(dǎo)致長(zhǎng)時(shí)間的STW,應(yīng)該要盡量避免啊易。
導(dǎo)致G1 Full GC的原因可能有兩個(gè):

  1. Evacuation的時(shí)候沒有足夠的to-space來(lái)存放晉升的對(duì)象吁伺;
  2. 并發(fā)處理過程完成之前空間耗盡

PS: 本文主要參考的國(guó)內(nèi)文章:
java Hotspot G1 GC的一些關(guān)鍵技術(shù)
Garbage First G1收集器 理解和原理分析
G1: One Garbage Collector To Rule Them All
請(qǐng)教G1算法的原理
深入理解 Java G1 垃圾收集器
Getting Started with the G1 Garbage Collector!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市租谈,隨后出現(xiàn)的幾起案子篮奄,更是在濱河造成了極大的恐慌,老刑警劉巖割去,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件窟却,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡呻逆,警方通過查閱死者的電腦和手機(jī)夸赫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)咖城,“玉大人茬腿,你說我怎么就攤上這事∫巳福” “怎么了滓彰?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)州袒。 經(jīng)常有香客問我揭绑,道長(zhǎng),這世上最難降的妖魔是什么郎哭? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任他匪,我火速辦了婚禮,結(jié)果婚禮上夸研,老公的妹妹穿的比我還像新娘邦蜜。我一直安慰自己,他們只是感情好亥至,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布悼沈。 她就那樣靜靜地躺著,像睡著了一般姐扮。 火紅的嫁衣襯著肌膚如雪絮供。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天茶敏,我揣著相機(jī)與錄音壤靶,去河邊找鬼。 笑死惊搏,一個(gè)胖子當(dāng)著我的面吹牛贮乳,可吹牛的內(nèi)容都是我干的忧换。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼向拆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼亚茬!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起浓恳,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤刹缝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后奖蔓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赞草,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年吆鹤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了厨疙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疑务,死狀恐怖沾凄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情知允,我是刑警寧澤撒蟀,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站温鸽,受9級(jí)特大地震影響保屯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜涤垫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一姑尺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蝠猬,春花似錦切蟋、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至匆绣,卻和暖如春驻右,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背犬绒。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工旺入, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凯力。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓茵瘾,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親咐鹤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拗秘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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