對G1垃圾收集器的了解

作為一款高效的垃圾收集器杜恰,G1在JDK7中加入JVM卒蘸,在JDK9中取代CMS成為了默認(rèn)的垃圾收集器鬓照。

1.1 新生代

新生代采用復(fù)制算法薛匪,主要的垃圾收集器有三個挟冠,Serial噩咪、Parallel New 和 Parallel Scavenge弄慰,特性如下:

Serial:單線程收集器勺远,串行方式運(yùn)行署尤,GC 進(jìn)行時耙替,其他線程都會停止工作。在單核 CPU 下曹体,收集效率最高俗扇。

Parallel New:Serial 的多線程版本,新生代默認(rèn)收集器箕别。在多核 CPU 下铜幽,效率更高,可以跟CMS收集器配合使用串稀。

Parallel Scavenge:多線程收集器除抛,更加注重吞吐量,適合交互少的任務(wù)母截,不能跟 CMS 配合使用到忽。

1.1 老年代

Serial Old:采用標(biāo)記-整理(壓縮)算法,單線程收集。

Parallel Old:采用標(biāo)記-整理(壓縮)算法喘漏,可以跟 Parallel Scavenge 配合使用

CMS:Concurrent Mark Sweep护蝶,采用標(biāo)記-清除算法,收集線程可以跟用戶線程一起工作翩迈。

CMS缺點(diǎn):吞吐量低持灰、無法處理浮動垃圾、標(biāo)記清除算法會產(chǎn)生大量內(nèi)存碎片负饲、并發(fā)模式失敗后會切到Serial old堤魁。

G1:把堆劃分成多個大小相等的Region,新生代和老年代不再物理隔離绽族,多核 CPU 和大內(nèi)存的場景下有很好的性能姨涡。新生代使用復(fù)制算法,老年代使用標(biāo)記-壓縮(整理)算法吧慢。



G1

G1垃圾收集器主要用于多處理器涛漂、大內(nèi)存的場景,它有五個屬性:分代检诗、增量匈仗、并行(大多時候可以并發(fā))、stop the word逢慌、標(biāo)記整理悠轩。

分代:跟其他垃圾收集器一樣,G1把堆分成了年輕代和老年代攻泼,垃圾收集主要在年輕代火架,并且年輕代回收效率最高。偶爾也會在老年代進(jìn)行回收忙菠。

增量:為了讓垃圾收集時STW時間更短何鸡,G1采用增量和分步進(jìn)行回收。G1通過對應(yīng)用之前的行為和停頓時間進(jìn)行分析構(gòu)建出可預(yù)測停頓時間模型牛欢,并且利用這個信息來預(yù)測停頓時間內(nèi)的垃圾收集情況骡男。比如:G1會首先回收那些收集效率高的內(nèi)存區(qū)域(這些區(qū)別大部分空間是可回收垃圾,這也是為啥叫G1的原因)傍睹。

并行和并發(fā):為了提高吞吐量隔盛,一些操作需要STW。一些需要花費(fèi)很多時間的操作拾稳,比如整堆操作(像全局標(biāo)記)可以并發(fā)執(zhí)行吮炕,同時可以并發(fā)跟應(yīng)用并行執(zhí)行

標(biāo)記整理:G1主要使用標(biāo)記整理算法來進(jìn)行垃圾收集访得,標(biāo)記階段跟“標(biāo)記清除”算法一樣来屠,但標(biāo)記之后不會直接對可回收對象進(jìn)?清理,?是讓所有存活對象都移動到一端,然后直接回收掉移動之后邊界以外的內(nèi)存俱笛。如下圖:

? ? ? 我們知道,垃圾收集器的一個目標(biāo)就是STW(stop the word)越短越好传趾。利用可預(yù)測停頓時間模型迎膜,G1為垃圾收集設(shè)定一個STW的目標(biāo)時間(通過 -XX:MaxGCPauseMillis 參數(shù)設(shè)定,默認(rèn)200ms)浆兰,G1盡可能地在這個時間內(nèi)完成垃圾收集磕仅,并且在不需要額外配置的情況下實(shí)現(xiàn)高吞吐量。

G1致力于在下面的應(yīng)用和環(huán)境下尋找延遲和吞吐量的最佳平衡:

堆大小達(dá)到10GB以上簸呈,并且一半以上的空間被存活的對象占用

隨著系統(tǒng)長期運(yùn)行榕订,對象分配和升級速率變化很快

堆中存在大量內(nèi)存碎片

垃圾收集時停頓時間不能超過幾百毫秒,避免垃圾收集造成的長時間停頓蜕便。

如果在JDK8中使用G1劫恒,我們可以使用參數(shù) -XX:+UseG1GC 來開啟。

G1并不是一款實(shí)時收集器轿腺,它盡最大努力以高性能完成 MaxGCPauseMillis 設(shè)置的停頓時間两嘴,但并不能絕對保證在這個時間內(nèi)完成收集。

2.2 堆布局

G1把整個堆分成了大小相等的region族壳,每一個region都是連續(xù)的虛擬內(nèi)存憔辫,region是內(nèi)存分配和回收的基本單位。如下圖:

紅色帶"S"的region表示新生代的survivor仿荆,紅色不帶"S"的表示新生代eden贰您,淺藍(lán)色不帶"H"的表示老年代,淺藍(lán)色帶"H"的表示老年代中的大對象拢操。跟G1之前的內(nèi)存分配策略不同的是,survivor庐冯、eden孽亲、老年代這些區(qū)域可能是不連續(xù)的。

G1在停頓的時候可以回收整個新生代的region展父,新生代region的對象要不復(fù)制到survivor區(qū)要不復(fù)制到老年代region返劲。同時每次停頓都可以回收一部分老年代的內(nèi)存,把老年代從一個region復(fù)制到另一個region栖茉。

2.3 關(guān)于region

上一節(jié)我們看到篮绿,整個堆內(nèi)存被G1分成了多個大小相等的region,每個堆大約可以有2048個region吕漂,每個region大小為 1~32 MB(必須是2的次方)亲配。region的大小通過 -XX:G1HeapRegionSize 來設(shè)置,所以按照默認(rèn)值來G1能管理的最大內(nèi)存大約 32MB * 2048 = 64G。

2.4 大對象

大對象是指大小超過了region一半的對象吼虎,大對象可以橫跨多個region犬钢,給大對象分配內(nèi)存的時候會直接分配在老年代,并不會分配在eden區(qū)思灰。

如下圖玷犹,一個大對象占據(jù)了兩個半region,給大對象分配內(nèi)存時洒疚,必須從一個region開始分配連續(xù)的region歹颓,在大對象被回收前,最后一個region不能被分配給其他對象油湖。

大對象什么時候回收巍扛?通常,只有在mark結(jié)束以后的Cleanup停頓階段或者FullGC的時候乏德,死亡的大對象才會被回收掉撤奸。但是,基本類型(比如bool數(shù)組鹅经、所有的整形數(shù)組寂呛、浮點(diǎn)型數(shù)組等)的數(shù)組大對象有個例外,G1會在任何GC停頓的時候回收這些死亡大對象。這個默認(rèn)是開啟的瘾晃,但是可以使用 -XX:G1EagerReclaimHumongousObjects 這個參數(shù)禁用掉贷痪。

分配大對象的時候,因?yàn)檎加每臻g太大蹦误,可能會過早發(fā)生GC停頓劫拢。G1在每次分配大對象的時候都會去檢查當(dāng)前堆內(nèi)存占用是否超過初始堆占用閾值IHOP(The Initiating Heap Occupancy Percent),如果當(dāng)前的堆占用率超過了IHOP閾值强胰,就會立刻觸發(fā) initial mark舱沧。關(guān)于initial mark詳見第4節(jié)

即使是在FullGC的時候偶洋,大對象也是永遠(yuǎn)不會被移動的熟吏。這可能導(dǎo)致過早發(fā)生FullGC或者是意外的OOM,因?yàn)榇藭r雖然還有大量的空閑內(nèi)存玄窝,但是這些內(nèi)存都是region中的內(nèi)存碎片牵寺。


內(nèi)存分配:

G1雖然把堆內(nèi)存劃分成了多個region,但是依然存在新生代和老年代的概念恩脂。G1新增了2個控制新生代內(nèi)存大小的參數(shù)帽氓,-XX:G1NewSizePercent(默認(rèn)等于5),-XX:G1MaxNewSizePercent(默認(rèn)等于60)俩块。也就是說新生代大小默認(rèn)占整個堆內(nèi)存的 5% ~ 60%黎休。

根據(jù)前面介紹浓领,一個堆大概可以分配2048個region,每個region最大32M势腮,這樣G1管理的整個堆的大小最大可以是64G联贩,新生代占用的大小范圍是 3.2G ~ 38.4G。

對于 -XX:G1NewSizePercent 和 -XX:G1MaxNewSizePercent捎拯,下面幾個問題需要注意:

如果設(shè)置了-Xmn撑蒜,那這兩個參數(shù)是否生效?

生效玄渗,比如堆大小是64G,設(shè)置 -Xmn3.2G狸眼,那么就等價于 -XX:G1NewSizePercent=5 并且 -XX:G1MaxNewSizePercent=5藤树,因?yàn)?.2G/64G = 5%。

如果設(shè)置了 -XX:NewRatio拓萌,這兩個參數(shù)是否生效岁钓?

生效,比如堆大小是64G微王,設(shè)置 -XX:NewRatio=3屡限,那么就等價于 -XX:G1NewSizePercent=25 并且 -XX:G1MaxNewSizePercent=25。因?yàn)槟贻p代:老年代 = 1 :3炕倘,說明年輕代占1/4 = 25%钧大。

如果 -XX:G1NewSizePercent 和 -XX:G1MaxNewSizePercent 只設(shè)置其中一個,那這兩個參數(shù)還生效嗎罩旋?

設(shè)置的這個參數(shù)不生效啊央,兩個參數(shù)都用默認(rèn)值。

如果-XX:G1NewSizePercent 和 -XX:G1MaxNewSizePercent 這兩個參數(shù)都生效了涨醋,什么時候動態(tài)擴(kuò)容瓜饥?

跟 -XX:GCTimeRatio 這個參數(shù)相關(guān)。這個參數(shù)為0~100之間的整數(shù)(G1默認(rèn)是9, 其它收集器默認(rèn)是99)浴骂,值為 n 則系統(tǒng)將花費(fèi)不超過 1/(1+n) 的時間用于垃圾收集乓土。因此G1默認(rèn)最多 10% 的時間用于垃圾收集,如果垃圾收集時間超過10%溯警,則觸發(fā)擴(kuò)容趣苏。如果擴(kuò)容失敗,則發(fā)起Full GC愧膀。



垃圾回收:

G1的垃圾收集是在 Young-Only 和 Space-Reclamation兩個階段交替執(zhí)行的拦键。如下圖:

young-only階段會用對象逐步把老年代區(qū)域填滿,space-reclamation階段除了會回收年輕代的內(nèi)存以外檩淋,還會增量回收老年代的內(nèi)存芬为。完成后重新開始young-only階段萄金。

4.1 Young-only

Young-only階段流程如下圖:

這個階段從普通的 young-only GC 開始,young-only GC把一些對象移動到老年代媚朦,當(dāng)老年代的空間占用達(dá)到IHOP時氧敢,G1就停止普通的young-only GC,開始初始標(biāo)記(Initial Mark)询张。

初始標(biāo)記:這個過程除了普通的 young-only GC 外孙乖,還會開始并發(fā)標(biāo)記過程,這個過程決定了被標(biāo)記的老年代存活對象在下一次space-reclamation階段會被保留份氧。這個過程不會STW唯袄,有可能標(biāo)記還沒有結(jié)束普通的 young-only GC 就開始了。這個標(biāo)記過程需要在重新標(biāo)記(Remark)和清理(Cleanup)兩個過程后才能結(jié)束蜗帜。

重新標(biāo)記: 這個過程會STW恋拷,這個過程做全局引用和類卸載。

在重新標(biāo)記和清理這兩個階段之間G1會并發(fā)計算對象存活信息厅缺,這個信息用于清理階段更新內(nèi)部數(shù)據(jù)結(jié)構(gòu)蔬顾。

清理階段:

這個節(jié)點(diǎn)回收所有的空閑區(qū)域,并且決定是否接著執(zhí)行一次space-reclamation湘捎,如果是诀豁,則僅僅執(zhí)行一次單獨(dú)的young-only GC,young-only階段就結(jié)束了窥妇。

關(guān)于IHOP舷胜,默認(rèn)情況下,G1會觀察標(biāo)記周期內(nèi)標(biāo)記花了多少時間秩伞,老年代分配了多少內(nèi)存逞带,以此來自動確定一個最佳的IHOP,這叫做自適應(yīng)IHOP纱新。如果開啟這個功能展氓,因?yàn)槌跏紩r沒有足夠的觀察數(shù)據(jù)來確定IHOP,G1會用參數(shù) -XX:InitiatingHeapOccupancyPercent 來指定初始IHOP脸爱∮龉可以用 -XX:-G1UseAdaptiveIHOP 參數(shù)關(guān)閉自適應(yīng)IHOP,這樣IHOP就參數(shù) -XX:InitiatingHeapOccupancyPercent 指定的固定值簿废。自適應(yīng)IHOP這樣設(shè)置老年代占有率,當(dāng)老年代占有率=老年代最大占有率 - 參數(shù) -XX:G1HeapReservePercent 值時空入,啟動space-reclamation階段的第一個Mixed GC。這里參數(shù) -XX:G1HeapReservePercent 作為一個額外的緩存值族檬。

關(guān)于標(biāo)記歪赢,標(biāo)記使用 SATB 算法,初始標(biāo)記開始時单料,G1保存堆的一份虛擬鏡像埋凯,這份鏡像存活的對象在后續(xù)的標(biāo)記過程中也被認(rèn)為是存活的点楼。這有一個問題,就是標(biāo)記過程中如果部分對象死亡了白对,對于 space-reclamation 階段來說它們?nèi)匀皇谴婊畹?也有少部分例外)掠廓。跟其他垃圾收集器相比,這會導(dǎo)致一部分死亡對象被錯誤保留甩恼,但是為標(biāo)記階段提供了更好的吞吐量蟀瞧,而且這些錯誤保留的對象會在下一次標(biāo)記階段被回收。

在young-only階段条摸,要回收新生代的region悦污。每一次 young-only 結(jié)束的時候,G1總是會調(diào)整新生代大小钉蒲。G1可以使用參數(shù) -XX:MaxGCPauseTimeMillis和 -XX:PauseTimeIntervalMillis 來設(shè)置目標(biāo)停頓時間塞关,這兩個參數(shù)是對實(shí)際停頓時間的長期觀察得來的。他會根據(jù)在GC的時候要拷貝多少個對象子巾,對象之間是如何相互關(guān)聯(lián)的等信息計算出來回收相同大小的新生代內(nèi)存需要花費(fèi)多少時間,

如果沒有其他的限定條件小压,G1會把young區(qū)的大小調(diào)整為 -XX:G1NewSizePercent和 -XX:G1MaxNewSizePercent 之間的值來滿足停頓時間的要求线梗。

4.2 Space-reclamation

這個階段由多個Mixed GC組成,不光回收年輕代垃圾怠益,也回收老年代垃圾仪搔。當(dāng) G1 發(fā)現(xiàn)回收更多的老年代區(qū)域不能釋放更多空閑空間時,這個階段結(jié)束蜻牢。之后烤咧,周期性地再次開啟一個新的Young-only階段。

當(dāng)G1收集存活對象信息時內(nèi)存不足抢呆,G1會做一個Full GC煮嫌,并且會STW。

在 space-reclamation 階段抱虐,G1會盡量在GC停頓時間內(nèi)回收盡可能多的老年代內(nèi)存昌阿。這個階段新生代內(nèi)存大小被調(diào)整為 -XX:G1NewSizePercent 設(shè)置的允許的最小值,只要存在可回收的老年代region就會被添加到回收集合中恳邀,直到再添加會超出目標(biāo)停頓時間為止懦冰。在特定的某個GC停頓時間內(nèi),G1會按照這老年代region回收的效率(效率高的優(yōu)先收集)和剩余可用時間來得到最終待回收region集合谣沸。

每一個GC停頓期間要回收的老年代region數(shù)量受限于候選region集合數(shù)量除以 -XX:G1MixedGCCountTarget 這個參數(shù)值刷钢,參數(shù) -XX:G1MixedGCCountTarget 指定一個周期內(nèi)觸發(fā)Mixed GC最大次數(shù),默認(rèn)值8乳附。比如 -XX:G1MixedGCCountTarget 采用默認(rèn)值8内地,候選region集合有200個region伴澄,那每次停頓期間收集25個region。

候選region集合是老年代中所有占用率低于 -XX:G1MixedGCLiveThresholdPercent 的region瓤鼻。

當(dāng)待回收region集合中可回收的空間占用率低于參數(shù)值 -XX:G1HeapWastePercent 的時候秉版,Space-Reclamation結(jié)束。

4.3 內(nèi)存緊張情況

當(dāng)應(yīng)用存活對象占用了大量內(nèi)存茬祷,以至于回收剩余對象沒有足夠的空間拷貝時清焕,就會觸發(fā) evacuation failure。這時G1為了完成當(dāng)前的垃圾收集祭犯,會保留已經(jīng)位于新的位置上的存活對象不動秸妥,對于沒有移動和拷貝的對象就不會進(jìn)行拷貝了,僅僅調(diào)整對象間的引用沃粗。

evacuation failure會導(dǎo)致一些額外的開銷粥惧,但是一般會跟其他 young GC 一樣快。evacuation failure完成以后最盅,G1會跟正常情況下一樣繼續(xù)恢復(fù)應(yīng)用的執(zhí)行突雪。G1會假設(shè) evacuation failure是發(fā)生在GC的后期,這時大部分對象已經(jīng)移動過了涡贱,并且已經(jīng)有足夠的內(nèi)存來繼續(xù)執(zhí)行應(yīng)用程序一直到 mark 結(jié)束 space-reclamation 開始咏删。如果這個假設(shè)不成立(也就是說沒有足夠的內(nèi)存來執(zhí)行應(yīng)用程序),G1最終只能發(fā)起Full GC问词,對整個堆做壓縮督函,這個過程可能會非常慢。



與其他垃圾收集器相比:

5.1 Parallel GC

Parallel GC 可以壓縮和回收老年代的內(nèi)存激挪,但是也只能對老年代整體來操作辰狡。G1以增量的方式把整個GC工作增量的分散到多個更短的停頓時間中,當(dāng)然這可能會犧牲一定吞吐量垄分。

5.2 CMS

跟CMS類似宛篇,G1并發(fā)回收老年代內(nèi)存,但是薄湿,CMS采用標(biāo)記-清除算法些己,不會處理老年代的內(nèi)存碎片,最終就會導(dǎo)致長時間的FullGC嘿般。

5.3 G1問題

因?yàn)椴捎貌l(fā)收集段标,G1的性能開銷會更大,這可能會影響吞吐量炉奴。

5.4 G1優(yōu)勢

G1在任何的GC期間都可以回收老年代中全空或者占用大空間的內(nèi)存逼庞。這可以避免一些不必要的GC,因?yàn)榭梢苑浅]p易地釋放大量的內(nèi)存空間瞻赶。這個功能默認(rèn)開啟赛糟,可以采用 -XX:-G1EagerReclaimHumongousObjects 參數(shù)關(guān)閉派任。

G1可以選擇對整個堆里面的String進(jìn)行并行去重。這個功能默認(rèn)關(guān)閉璧南,可以使用參數(shù) -XX:+G1EnableStringDeduplication 來開啟掌逛。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市司倚,隨后出現(xiàn)的幾起案子豆混,更是在濱河造成了極大的恐慌,老刑警劉巖动知,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件皿伺,死亡現(xiàn)場離奇詭異,居然都是意外死亡盒粮,警方通過查閱死者的電腦和手機(jī)鸵鸥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丹皱,“玉大人妒穴,你說我怎么就攤上這事√福” “怎么了宰翅?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長爽室。 經(jīng)常有香客問我,道長淆攻,這世上最難降的妖魔是什么阔墩? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮瓶珊,結(jié)果婚禮上啸箫,老公的妹妹穿的比我還像新娘。我一直安慰自己伞芹,他們只是感情好忘苛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唱较,像睡著了一般扎唾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上南缓,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天胸遇,我揣著相機(jī)與錄音,去河邊找鬼汉形。 笑死纸镊,一個胖子當(dāng)著我的面吹牛倍阐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播逗威,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼峰搪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凯旭?” 一聲冷哼從身側(cè)響起概耻,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎尽纽,沒想到半個月后咐蚯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弄贿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年春锋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片差凹。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡期奔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出危尿,到底是詐尸還是另有隱情呐萌,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布谊娇,位于F島的核電站肺孤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏济欢。R本人自食惡果不足惜赠堵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望法褥。 院中可真熱鬧茫叭,春花似錦、人聲如沸半等。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽杀饵。三九已至莽囤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間切距,已是汗流浹背烁登。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饵沧。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓锨络,卻偏偏與公主長得像,于是被迫代替她去往敵國和親狼牺。 傳聞我的和親對象是個殘疾皇子羡儿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

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