一、何為G1收集器
The Garbage-First (G1) garbage collector is a server-style garbage collector, targeted for multiprocessor machines with large memories. It attempts to meet garbage collection (GC) pause time goals with high probability while achieving high throughput. Whole-heap operations, such as global marking, are performed concurrently with the application threads. This prevents interruptions proportional to heap or live-data size.
Garbage First(簡稱G1)收集器是垃圾收集器技術(shù)發(fā)展史上里程碑式的成果,它開創(chuàng)了收集器面向局部收集的設(shè)計(jì)思路和基于Region的內(nèi)存布局形式。
作為CMS收集器的替代者和繼承人,設(shè)計(jì)者們希望做出一款能夠建立起“停頓時(shí)間模型”的收集器饥努,停頓時(shí)間模型的意思是能夠支持指定在一個(gè)長度為M毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間大概率不超過N秒這樣的目標(biāo)。
二帆焕、G1收集器內(nèi)存管理
1、Mixed GC模式
G1的里程碑意義來源于其面向局部收集的設(shè)計(jì)思路和基于Region的內(nèi)存布局形式不恭,這也是G1實(shí)現(xiàn)其停頓時(shí)間模型的底氣叶雹。在G1收集器出現(xiàn)之前的所有其他收集器,包括被它所替代的CMS换吧,垃圾收集的目標(biāo)范圍都是整個(gè)新生代(Minor GC)或整個(gè)老年代(Major GC)折晦,亦或者是整個(gè)Java堆(Full GC)。而G1實(shí)現(xiàn)了可以面向堆內(nèi)存的任何部分來組成回收集沾瓦。衡量標(biāo)準(zhǔn)不再是分代满着,而是回收的實(shí)際收益,這就是Mixed GC模式贯莺。
2风喇、基于Region的堆內(nèi)存布局
G1基于Region的堆內(nèi)存布局是它實(shí)現(xiàn)Mixed GC的關(guān)鍵。我們不能說G1擯棄了分代理論缕探,相反魂莫,G1依然是依據(jù)分代理論設(shè)計(jì)的,但其堆內(nèi)存布局與其他收集器有非常明顯的差異爹耗,它不再堅(jiān)持固定大小以及固定數(shù)量的分代區(qū)域劃分耙考,而是把堆分成多個(gè)大小相等的獨(dú)立區(qū)域谜喊,稱為Region,而每個(gè)Region都可能是新生代或老年代倦始。這樣無論是針對哪種對象斗遏,都可以有比較好的收集效果。
從上圖中我們可以看見鞋邑,Region中還有一種Humongous區(qū)域最易,它專門用來存儲(chǔ)大對象。G1認(rèn)為一個(gè)對象的大小超過了一個(gè)Region的一半炫狱,那就可以稱為大對象藻懒。如果對象大小超過一個(gè)Region,就存儲(chǔ)在連續(xù)的多個(gè)Region當(dāng)中视译。另外值得注意的是嬉荆,G1的大部分行為都把Humongous Region作為老年代的一部分來看待。
3酷含、G1具有優(yōu)先級的區(qū)域回收方式
G1之所以能夠建立起可預(yù)測的停頓時(shí)間模型鄙早,是因?yàn)樗鼘egion作為單次回收的最小單元。G1收集器會(huì)跟蹤每個(gè)Region中垃圾總的“價(jià)值”大小椅亚,即回收所獲得的空間大小和回收所需時(shí)間的經(jīng)驗(yàn)值限番,然后在后臺(tái)維護(hù)一個(gè)優(yōu)先級列表。并可以根據(jù)用戶的設(shè)定回收價(jià)值收益最大的Region呀舔。這也是“Garbage First”其名的由來弥虐。
三、G1收集器開發(fā)者花大量時(shí)間解決的三個(gè)尖銳問題
G1收集器作為一款跨時(shí)代的收集器媚赖,它從發(fā)表論文到商用經(jīng)歷了超過十年的研發(fā)霜瘪,其中解決了無數(shù)的問題,以下是三個(gè)典型且重要的問題向讀者說明惧磺。
1颖对、跨Region引用問題如何解決?
和其他收集器解決跨代問題的方法一樣磨隘,G1使用記憶集從而避免全堆作為GC Roots掃描缤底。但不同的是G1的每個(gè)Region都維護(hù)屬于自己的記憶集,它們會(huì)記錄下別的Region指向自己的指針番捂,并標(biāo)記這些指針分別在哪些卡頁的范圍內(nèi)个唧。G1的記憶集在存儲(chǔ)結(jié)構(gòu)的本質(zhì)上是哈希表(key是別的Region的起始地址,Value是卡表索引號的集合)白嘁。
由于Region的數(shù)量較多坑鱼,而每個(gè)Region都有自己的記憶集,所以G1收集器要花費(fèi)更大的內(nèi)存來維持工作,這個(gè)數(shù)通常是Java堆的10%~20%鲁沥。
2呼股、在并發(fā)階段如何保證收集線程與用戶線程互不干擾地運(yùn)行?
首先画恰,用戶線程改變對象引用關(guān)系時(shí)彭谁,必須保證不打破原本的對象圖結(jié)構(gòu),導(dǎo)致標(biāo)記結(jié)果出現(xiàn)錯(cuò)誤允扇。CMS對這個(gè)問題采取了增量更新的算法進(jìn)行解決缠局,而G1選擇了原始快照(SATB)的方法進(jìn)行解決。
其次考润,回收過程中會(huì)有新對象需要進(jìn)行內(nèi)存分配狭园。G1為每個(gè)Region設(shè)置了兩個(gè)名為TAMS的指針,把Region的一部分空間用于并發(fā)回收過程中的新對象分配糊治。新對象的地址必須在這兩個(gè)指針之上唱矛。這部分空間被收集器視為默認(rèn)存貨, 不納入回收范圍井辜。
3绎谦、怎樣建立起可靠的停頓預(yù)測模型?
G1收集器的停頓預(yù)測模型是以衰減均值作為理論基礎(chǔ)來實(shí)現(xiàn)的粥脚。在垃圾收集過程中窃肠,G1收集器會(huì)記錄每個(gè)Region的回收時(shí)間、記憶集中的臟卡數(shù)量等各個(gè)步驟的成本刷允,并按照一定的統(tǒng)計(jì)信息和統(tǒng)計(jì)算法得出“衰減平均值”冤留。衰減平均值更準(zhǔn)確地代表了最近的平均狀態(tài),Region的統(tǒng)計(jì)狀態(tài)越新就越能決定回收的價(jià)值恃锉。
根據(jù)這些信息搀菩,收集器可以決定應(yīng)當(dāng)找出哪些Region進(jìn)入回收集呕臂,最終在不超過期望時(shí)間的前提下獲得最高收益破托。
四、G1收集器實(shí)際運(yùn)作的四大步驟
1歧蒋、初始標(biāo)記
標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象土砂。并且修改TAMS的值,讓并發(fā)標(biāo)記階段分配對象有據(jù)可依谜洽。這個(gè)階段需要停頓線程萝映,但耗時(shí)很短,并且在Minor GC時(shí)同步完成阐虚。
2序臂、并發(fā)標(biāo)記
從GC Root中開始對堆中對象進(jìn)行可達(dá)性分析,掃描對象圖,找出要回收的對象奥秆,這階段耗時(shí)長但是可以和用戶程序并發(fā)執(zhí)行逊彭。當(dāng)對象圖掃描完成后,還要重新處理SATB記錄下的在并發(fā)時(shí)有引用變動(dòng)的對象构订。
3侮叮、最終標(biāo)記
對用戶線程做一個(gè)短暫的暫停,用于處理并發(fā)階段結(jié)束后仍遺留下來的最后那些少量的SATB記錄悼瘾。
4囊榜、篩選回收
負(fù)責(zé)更新Region的統(tǒng)計(jì)數(shù)據(jù),對各個(gè)Region的回收價(jià)值和成本進(jìn)行排序亥宿,制定具體的回收計(jì)劃卸勺。可以自由地選擇多個(gè)Region作為回收集烫扼,把其中存活的對象復(fù)制到空的Region中孔庭,再清理掉整個(gè)回收集。由于涉及存活對象的移動(dòng)材蛛,所以必須暫停用戶線程圆到。
總之,G1收集器的設(shè)計(jì)目標(biāo)是在延遲可控的前提下獲得盡可能高的吞吐量卑吭。
五芽淡、G1收集器與CMS收集器的比較
作為兩款關(guān)注停頓時(shí)間的收集器,G1常被作為CMS收集器的比較對象豆赏。在今天挣菲,G1已經(jīng)幾乎完全取代了CMS的地位,但這并不意味著CMS在G1面前不值一提掷邦。
先說明一個(gè)事實(shí):在小內(nèi)存上CMS的表現(xiàn)可能會(huì)優(yōu)于G1白胀,而大內(nèi)存上G1毫無疑問會(huì)占據(jù)優(yōu)勢。這個(gè)堆內(nèi)存大小的平衡點(diǎn)通常在6~8GB左右抚岗。
1或杠、G1的新設(shè)計(jì)帶來的優(yōu)勢
指定最大停頓時(shí)間、分Region的內(nèi)存布局宣蔚、按收益確定最終回收集向抢,這些都是G1的新設(shè)計(jì)給它帶來的相對于CMS的優(yōu)勢。
2胚委、整體收集算法的不同
CMS集于標(biāo)記-清除算法進(jìn)行收集挟鸠,而G1從整體看集于標(biāo)記-整理算法進(jìn)行收集,局部看基于標(biāo)記-復(fù)制算法進(jìn)行收集亩冬。顯然艘希,G1的兩種解讀方法都意味著它不會(huì)產(chǎn)生任何內(nèi)存碎片。這樣的特性有利于程序長久地平穩(wěn)運(yùn)行。
3覆享、內(nèi)存消耗不同
我們前文中提到鸠姨,G1收集器為每一個(gè)Region都提供了卡表作為記憶集,顯然這意味著G1相比CMS需要消耗更大量的內(nèi)存來完成其本職工作淹真。相比之下CMS的卡表僅有一份且實(shí)現(xiàn)簡單讶迁。
4、執(zhí)行負(fù)載不同
CMS使用寫后屏障來更新和維護(hù)卡表核蘸。G1除了使用寫后屏障巍糯,為了實(shí)現(xiàn)快照搜索算法,它還得使用寫前屏障來跟蹤并發(fā)時(shí)的指針變化情況客扎。這也引出了原始快照和增量更新兩種方法的比較:原始快照能夠減少并發(fā)標(biāo)記和重新標(biāo)記階段的損耗祟峦,避免在標(biāo)記階段停頓時(shí)間過長,但它同時(shí)也會(huì)產(chǎn)生由于跟蹤引用變化帶來的額外負(fù)擔(dān)徙鱼。
由于G1寫屏障的復(fù)雜操作要比CMS消耗更多的運(yùn)算資源宅楞,CMS的寫屏障實(shí)現(xiàn)是直接的同步操作,而G1必須把它實(shí)現(xiàn)為類似消息隊(duì)列的架構(gòu)袱吆,即把寫前屏障和寫后屏障要做的事都放到隊(duì)列里厌衙,然后異步處理。