ZGC 原理是什么,它為什么能做到低延時(shí)扫夜?

ZGC的成績(jī)是锅睛,無論你開了多大的堆內(nèi)存(1288G? 2T历谍?),硬是能保證低于10毫秒的JVM停頓辣垒。

SPECjbb 2015基準(zhǔn)測(cè)試望侈,在128G的大堆下,最大停頓時(shí)間才 1.68ms (不是平均勋桶,不是90%脱衙,99%,是Max ! )例驹,遠(yuǎn)低于最初的目標(biāo)-那保守的10ms捐韩,也遠(yuǎn)勝前代的G1。

大家的第一反應(yīng)都是這么顛覆性的東西怎么來的鹃锈,G1 通過每次只回收部分Region而不是全堆荤胁,改善了大堆下的停頓時(shí)間,但在普通大小的堆里表現(xiàn)并沒驚喜∈赫現(xiàn)在怎么突然就翻天了仅政,一點(diǎn)心理準(zhǔn)備都沒有啊。

如果文章太長(zhǎng)不想看下去盆驹,你只要記住R大下面這句話就夠了:

與標(biāo)記對(duì)象的傳統(tǒng)算法相比圆丹,ZGC在指針上做標(biāo)記,在訪問指針時(shí)加入Load Barrier(讀屏障)躯喇,比如當(dāng)對(duì)象正被GC移動(dòng)辫封,指針上的顏色就會(huì)不對(duì),這個(gè)屏障就會(huì)先把指針更新為有效地址再返回,也就是倦微,永遠(yuǎn)只有單個(gè)對(duì)象讀取時(shí)有概率被減速妻味,而不存在為了保持應(yīng)用與GC一致而粗暴整體的Stop The World。

其實(shí)Azul JDK的皇牌 C4 垃圾收集 璃诀,早就同樣以最高十毫秒停頓成為江湖傳說弧可。 曾在Azul的R大, 看著JDK11 ZGC的算法和結(jié)果倍感熟悉劣欢,與ZGC的領(lǐng)隊(duì)Per Liden大大聊完之后棕诵,確認(rèn)了ZGC跟Azul Pauseless GC,是凿将,等校套,價(jià),的

[圖片上傳失敗...(image-68a273-1648567376486)]

下面讓我們來繼續(xù)聊聊ZGC的八大特征牧抵。

一笛匙、所有階段幾乎都是并發(fā)執(zhí)行的

這里的并發(fā)(Concurrent),說的是應(yīng)用線程與GC線程齊頭并進(jìn)犀变,互不添堵妹孙。

說幾乎,就是還有三個(gè)非常短暫的STW的階段获枝,所以ZGC并不是Zero Pause GC啦蠢正。

R大:“比如開始的Pause Mark Start階段,要做根集合(root set)掃描省店,包括全局變量啊嚣崭、線程棧啊啥的里面的對(duì)象指針,但不包括GC堆里的對(duì)象指針懦傍,所以這個(gè)暫停就不會(huì)隨著GC堆的大小而變化(不過會(huì)根據(jù)線程的多少啊雹舀、線程棧的大小之類的而變化)” -- 因此ZGC可以拍胸脯,無論堆多大停頓都小于10ms粗俱。

二说榆、并發(fā)執(zhí)行的保證機(jī)制,就是Colored Pointer 和 Load Barrier

原理前面R大一句話已經(jīng)說完了寸认。Colored Pointer 從64位的指針中娱俺,借了幾位出來表示Finalizable、Remapped废麻、Marked1荠卷、Marked0。 所以它不支持32位指針也不支持壓縮指針烛愧, 且堆的上限是4TB油宜。

image.png

有Load barrier在掂碱,就會(huì)在不同階段,根據(jù)指針顏色看看要不要做些特別的事情(Slow Path)慎冤。注意下圖里只有第一種語句需要讀屏障疼燥,后面三種都不需要,比如值是原始類型的時(shí)候蚁堤。

image.png

R大還提到了ZGC的Load Value Barrier醉者,與Red Hat的Shenandoah收集器的不同,后者選擇了70年代的比較基礎(chǔ)的Brooks Pointer 披诗,而前者在也是很老的Baker barrier上加入了self healing的特性撬即,比如下面的代碼:

Object a = obj.x;

Object b = obj.x;

兩行代碼都插入了讀屏障,但ZGC在第一個(gè)讀屏障之后呈队,不但a的值是新的剥槐,self healing下obj.x的值自身也會(huì)修正,第二個(gè)讀屏障時(shí)就直接進(jìn)入FastPath宪摧,沒有消耗了粒竖; 而Shenandoah 則不會(huì)修正obj.x的值,第二個(gè)讀屏障又要SlowPath一次几于。

三蕊苗、像G1一樣劃分Region,但更加靈活

ZGC將堆劃分為Region作為清理沿彭,移動(dòng)岁歉,以及并行GC線程工作分配的單位。

不過G1一開始就把堆劃分成固定大小的Region膝蜈,而ZGC 可以有2MB,32MB熔掺,N× 2MB 三種Size Groups饱搏,動(dòng)態(tài)地創(chuàng)建和銷毀Region,動(dòng)態(tài)地決定Region的大小置逻。

256k以下的對(duì)象分配在Small Page推沸, 4M以下對(duì)象在Medium Page,以上在Large Page券坞。

所以ZGC能更好的處理大對(duì)象的分配鬓催。

image.png

四、和G1一樣會(huì)做Compacting-壓縮

CMS是Mark-Sweep標(biāo)記過期對(duì)象后原地回收恨锚,這樣就會(huì)造成內(nèi)存碎片宇驾,越來越難以找到連續(xù)的空間,直到發(fā)生Full GC才進(jìn)行壓縮整理猴伶。

ZGC是Mark-Compact 课舍,會(huì)將活著的對(duì)象都移動(dòng)到另一個(gè)Region塌西,整個(gè)回收掉原來的Region。

而G1 是 incremental copying collector筝尾,一樣會(huì)做壓縮捡需。

下面粗略了幾十倍地過一波回收流程,小階段都被略過了哈:

1. Pause Mark Start -初始停頓標(biāo)記

停頓JVM地標(biāo)記Root對(duì)象筹淫,1站辉,2,4三個(gè)被標(biāo)為live损姜。

2. Concurrent Mark -并發(fā)標(biāo)記

并發(fā)地遞歸標(biāo)記其他對(duì)象饰剥,5和8也被標(biāo)記為live。

3. Relocate - 移動(dòng)對(duì)象

對(duì)比發(fā)現(xiàn)3薛匪、6捐川、7是過期對(duì)象,也就是中間的兩個(gè)灰色region需要被壓縮清理逸尖,所以陸續(xù)將4古沥、5、8 對(duì)象移動(dòng)到最右邊的新Region娇跟。移動(dòng)過程中岩齿,有個(gè)forward table紀(jì)錄這種轉(zhuǎn)向。

R大這里又贊揚(yáng)了一下C4/ZGC的Quick Release特性:活的對(duì)象都移走之后苞俘,這個(gè)region可以立即釋放掉盹沈,并且用來當(dāng)作下一個(gè)要掃描的region的to region。所以理論上要收集整個(gè)堆吃谣,只需要有一個(gè)空region就OK了乞封。

而RedHat的Shenandoah 因?yàn)樗膄orward pointer的設(shè)計(jì),則需要有1/2個(gè)Heap是空的岗憋。

4. Remap - 修正指針

最后將指針都妥帖地更新指向新地址肃晚。這里R大還提到一個(gè)亮點(diǎn): “上一個(gè)階段的Remap,和下一個(gè)階段的Mark是混搭在一起完成的仔戈,這樣非常高效关串,省卻了重復(fù)遍歷對(duì)象圖的開銷〖嗯牵”

五晋修、沒有G1占內(nèi)存的Remember Set,沒有Write Barrier的開銷

G1 保證“每次GC停頓時(shí)間不會(huì)過長(zhǎng)”的方式凰盔,是“每次只清理一部分而不是全部的Region”的增量式清理墓卦。

那獨(dú)立清理某個(gè)Region時(shí) , 就需要有RememberSet來記錄Region之間的對(duì)象引用關(guān)系, 這樣就能依賴它來輔助計(jì)算對(duì)象的存活性而不用掃描全堆户敬, RS通常占了整個(gè)Heap的20%或更高趴拧。

這里還需要使用Write Barrier(寫屏障)技術(shù)溅漾,G1在平時(shí)寫引用時(shí),GC移動(dòng)對(duì)象時(shí)著榴,都要同步去更新RememberSe添履,跟蹤跨代跨Region間的引用,特別的重脑又。而CMS里只有新老生代間的CardTable暮胧,要輕很多。

ZGC幾乎沒有停頓问麸,所以劃分Region并不是為了增量回收往衷,每次都會(huì)對(duì)所有Region進(jìn)行回收,所以也就不需要這個(gè)占內(nèi)存的RememberSet了严卖,又因?yàn)樗鼤簳r(shí)連分代都還沒實(shí)現(xiàn)席舍,所以完全沒有Write Barrier。

六哮笆、支持Numa架構(gòu)

現(xiàn)在多CPU插槽的服務(wù)器都是Numa架構(gòu)了来颤,比如兩顆CPU插槽(24核),64G內(nèi)存的服務(wù)器稠肘,那其中一顆CPU上的12個(gè)核福铅,訪問從屬于它的32G本地內(nèi)存,要比訪問另外32G遠(yuǎn)端內(nèi)存要快得多项阴。

JDK的 Parallel Scavenger 算法支持Numa架構(gòu)滑黔,在SPEC JBB 2005 基準(zhǔn)測(cè)試?yán)铽@得40%的提升。

原理嘛环揽,就是申請(qǐng)堆內(nèi)存時(shí)略荡,對(duì)每個(gè)Numa Node的內(nèi)存都申請(qǐng)一些,當(dāng)一條線程分配對(duì)象時(shí)歉胶,根據(jù)當(dāng)前是哪個(gè)CPU在運(yùn)行的汛兜,就在靠近這個(gè)CPU的內(nèi)存中分配,這條線程繼續(xù)往下走跨扮,通常會(huì)重新訪問這個(gè)對(duì)象,而且如果線程還沒被切換出去验毡,就還是這位CPU同志在訪問衡创,所以就快了。

但可惜CMS晶通,G1不支持Numa璃氢,現(xiàn)在ZGC 又重新做了簡(jiǎn)單支持,哈哈哈狮辽。

R大補(bǔ)充一也,G1也打算支持了Numa了: http://openjdk.java.net/jeps/157

七巢寡、并行

在ZGC 官網(wǎng)上有介紹,前面基準(zhǔn)測(cè)試中的32核服務(wù)器椰苟,128G堆的場(chǎng)景下抑月,它的配置是:

20條ParallelGCThreads,在那三個(gè)極短的STW階段并行的干活 - mark roots舆蝴, weak root processing(StringTable, JNI Weak Handles,etc)和 relocate roots 谦絮;

4條ConcGCThreads,在其他階段與應(yīng)用并發(fā)地干活 - Mark洁仗,Process Reference层皱,Relocate。 僅僅四條赠潦,高風(fēng)亮節(jié)地盡量不與應(yīng)用爭(zhēng)搶CPU 叫胖。

ConcCGCThreads開始時(shí)各自忙著自己平均分配下來的Region,如果有線程先忙完了她奥,會(huì)嘗試“偷”其他線程還沒做的Region來干活瓮增,非常勤奮。

八方淤、單代

沒分代钉赁,應(yīng)該是ZGC唯一的弱點(diǎn)了。所以R大說ZGC的水平携茂,處于AZul早期的PauselessGC 與 分代的C4算法之間 - C4在代碼里就叫GPGC你踩,Generational Pauseless GC。

分代原本是因?yàn)閙ost object die young的假設(shè)讳苦,而讓新生代和老生代使用不同的GC算法带膜。但C4已經(jīng)是全程并發(fā)算法了,為什么還要分代呢鸳谜?

R大說:

“因?yàn)榉执腃4能承受的對(duì)象分配速度(Allocation Rate)膝藕, 大概是原始PGC的10倍。

如果對(duì)整個(gè)堆做一個(gè)完整并發(fā)收集周期咐扭,持續(xù)的時(shí)間可能很長(zhǎng)比如幾分鐘芭挽,而此期間新創(chuàng)建的對(duì)象,大致上只能當(dāng)作活對(duì)象來處理蝗肪,即使它們?cè)谶@周期里其實(shí)早就死掉可以被收集了袜爪。如果有分代算法,新生對(duì)象都在一個(gè)專門的區(qū)域創(chuàng)建薛闪,專門針對(duì)這個(gè)區(qū)域的收集能更頻繁更快辛馆,意外留活的對(duì)象更也少。

而Per大大因?yàn)榉执鷮?shí)現(xiàn)起來麻煩豁延,就先實(shí)現(xiàn)出比較簡(jiǎn)單可用的單代版本昙篙。所以ZGC如果遇上非常高的對(duì)象分配速率腊状,目前唯一有效的“調(diào)優(yōu)”方式就是增大整個(gè)GC堆的大小來讓ZGC有更大的喘息空間√桑”

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缴挖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子硕蛹,更是在濱河造成了極大的恐慌醇疼,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件法焰,死亡現(xiàn)場(chǎng)離奇詭異秧荆,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)埃仪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門乙濒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人卵蛉,你說我怎么就攤上這事颁股。” “怎么了傻丝?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵甘有,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我葡缰,道長(zhǎng)亏掀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任泛释,我火速辦了婚禮滤愕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘怜校。我一直安慰自己间影,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布茄茁。 她就那樣靜靜地躺著魂贬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裙顽。 梳的紋絲不亂的頭發(fā)上付燥,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音锦庸,去河邊找鬼机蔗。 笑死蒲祈,一個(gè)胖子當(dāng)著我的面吹牛甘萧,可吹牛的內(nèi)容都是我干的萝嘁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼扬卷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼牙言!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起怪得,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤咱枉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后徒恋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚕断,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年入挣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了亿乳。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡径筏,死狀恐怖葛假,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滋恬,我是刑警寧澤聊训,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站恢氯,受9級(jí)特大地震影響带斑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜酿雪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一遏暴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧指黎,春花似錦朋凉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吓揪,卻和暖如春亲怠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柠辞。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工团秽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓习勤,卻偏偏與公主長(zhǎng)得像踪栋,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子图毕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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