自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

G1回收器:我怎么知道你是什么時(shí)候的垃圾?

開(kāi)發(fā) 前端
借助“三色標(biāo)記”大法分析了垃圾回收線程掃描的過(guò)程中,用戶線程同時(shí)執(zhí)行修改引用關(guān)系的操作時(shí),可能會(huì)出現(xiàn)的“對(duì)象消失”問(wèn)題,以及其對(duì)應(yīng)的兩種解決方案.

 [[328451]]

上面的圖片是我上周末在家拍的。以后的文章里面我的第一張配圖都用自己隨手拍下的照片吧。分享生活,分享技術(shù),哈哈。

陽(yáng)臺(tái)上的花開(kāi)了,成都的春天快來(lái)了,疫情也應(yīng)該快要過(guò)去了吧。

最近在看《霍亂時(shí)期的愛(ài)情》,不知道為什么和《大話西游》聯(lián)系了起來(lái),所以你可以看到玻璃上的倒影,是我在看《大話西游》。

誰(shuí)都曾經(jīng)有過(guò)大鬧天宮的夢(mèng)想,愛(ài)上層樓的憂愁,但是早晚有一天,你也會(huì)像他轉(zhuǎn)身之后一樣,走在路上,像一條狗。

好了,說(shuō)回文章。

[[328452]]

 

讓你看看“浮動(dòng)垃圾”

上周《面試官:你說(shuō)你熟悉jvm?那你講一下并發(fā)的可達(dá)性分析》這篇文章主要聊了jvm的可達(dá)性分析算法。

借助“三色標(biāo)記”大法分析了垃圾回收線程掃描的過(guò)程中,用戶線程同時(shí)執(zhí)行修改引用關(guān)系的操作時(shí),可能會(huì)出現(xiàn)的“對(duì)象消失”問(wèn)題,以及其對(duì)應(yīng)的兩種解決方案

增量更新和原始快照。

在文章中我寫(xiě)道:對(duì)象關(guān)系圖的變化會(huì)導(dǎo)致出現(xiàn)兩種情況一是“浮動(dòng)垃圾”,二是“對(duì)象消失”。大概率的情況下面試官更加關(guān)心第二種情況,因?yàn)榈诙N情況會(huì)給程序帶來(lái)異常。接下來(lái)我就做動(dòng)圖分析了“對(duì)象消失”的情況。

但是我是萬(wàn)萬(wàn)沒(méi)想到呀,讀者更關(guān)心的是“浮動(dòng)垃圾”。有的讀者就來(lái)問(wèn)我,浮動(dòng)垃圾是怎么產(chǎn)生的,你倒是給個(gè)圖啊。

 

像我這樣的又暖又有料的硬核原創(chuàng)作者,你說(shuō)你要,那我肯定是要給你的。

下面就給你補(bǔ)上“浮動(dòng)垃圾”的動(dòng)圖:

 

當(dāng)并發(fā)標(biāo)記完成后,對(duì)象圖就變成了下面這個(gè)樣子:

 

你看出來(lái)了吧。對(duì)象7,8,4,11,10都是浮動(dòng)垃圾。因?yàn)樗麄儽粯?biāo)記成了黑色,所以逃過(guò)了本次垃圾回收。

什么?你問(wèn)我為什么黑色就不回收了?你個(gè)假粉絲,建議你先去讀一讀上周的推文。

[[328454]]

 

G1垃圾回收時(shí)新對(duì)象怎么處理?

有的讀者就提出了另外的很有探討性的問(wèn)題:

why哥你好,你《面試官:你說(shuō)你熟悉jvm?那你講一下并發(fā)的可達(dá)性分析》這篇文章主要解決了在并發(fā)標(biāo)記階段,GC線程和用戶線程并發(fā)執(zhí)行時(shí),用戶線程修改了對(duì)象引用關(guān)系,導(dǎo)致“對(duì)象消失”的問(wèn)題。G1是采用原始快照加寫(xiě)前屏障的方式解決這個(gè)問(wèn)題的。

但是我還有另外的一個(gè)問(wèn)題:用戶線程執(zhí)行時(shí)不僅修改了對(duì)象引用關(guān)系,還新分配了新對(duì)象,我覺(jué)得這個(gè)情況是非常常見(jiàn)的,G1是如何找到并處理這些對(duì)象的呢?

換句話說(shuō),就是文章標(biāo)題啦:G1收集器是怎么知道這些對(duì)象是什么時(shí)候應(yīng)該進(jìn)行垃圾標(biāo)記的?

這是一個(gè)好問(wèn)題,一看就是用心讀了文章并帶有自己的思考。很不錯(cuò)。

這位讀者的問(wèn)題屬于第一個(gè)問(wèn)題的連環(huán)炮,讓我突然有了一種掉進(jìn)了面試官布好的天羅地網(wǎng)里面的感覺(jué)。

面試官先故意漏出破綻,讓你聊“對(duì)象消失”、“三色標(biāo)記”、“增量更新”。然后等你得意洋洋的時(shí)候,突然拋出第二個(gè)問(wèn)題:剛剛對(duì)象消失的問(wèn)題回答的不錯(cuò),那如果并發(fā)標(biāo)記的時(shí)候用戶線程分配了新對(duì)象,G1是怎么處理的呢?

[[328455]]

 

說(shuō)實(shí)話,我覺(jué)得只要你簡(jiǎn)歷上沒(méi)有寫(xiě)精通jvm,面試一般問(wèn)到這種程度的我覺(jué)得是真的到了探討的地步了。答的上來(lái)加分,答不上來(lái)也不扣分。

遙想2016年,我剛畢業(yè),只身闖北京的時(shí)候,一連面試了9家公司,沒(méi)有一家公司聊到 jvm (當(dāng)然我當(dāng)時(shí)面的是初級(jí)開(kāi)發(fā))。現(xiàn)在不一樣了,不知道什么時(shí)候 jvm 從進(jìn)階面試題,變成了初級(jí)面試題。面試階段如果沒(méi)有問(wèn) jvm ,就感覺(jué)不是一次完整的面試。

我覺(jué)得就這幾年面試題的變化,其實(shí)也就是反映了一個(gè)現(xiàn)象:想入行的人越來(lái)越多,導(dǎo)致入行的門(mén)檻越來(lái)越高。

不是jvm的地位變了,而是門(mén)檻越來(lái)越高了。

 

好了,瞎逼逼完了,接下來(lái)我們聊聊G1。

初識(shí)Garbage First(G1)

我不知道你是怎么知道G1的,但是我是從周志明大大的《深入理解Java虛擬機(jī)(第2版)》這本書(shū)里面第一次知道G1收集器的。

我記得當(dāng)時(shí)讀到G1的時(shí)候感覺(jué)這就是天書(shū)啊。

因?yàn)樽髡咴诮榻BG1之前介紹了很多其他的收集器,我先給你看一下目錄,帶你回顧回顧:

 

可以看到,3.5.1節(jié)到3.5.6節(jié)介紹的收集器工作的時(shí)候, Java 堆的內(nèi)存布局是按照新生代,老年代進(jìn)行整體的區(qū)域劃分的。

但是到了G1收集器, Java 堆的內(nèi)存布局就有點(diǎn)"妖艷賤貨"了。然后就有點(diǎn)越來(lái)越看不懂了,當(dāng)時(shí)的場(chǎng)景就像下面這樣:

[[328456]]

 

它雖然還是保留的有新生代和老年代的概念,但是新生代和老年代之前再也不是區(qū)域上的隔離了。它將整個(gè) Java 堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域,叫做 Region 。而新生代和老年代就是由一個(gè)個(gè) Region 動(dòng)態(tài)組成的區(qū)域,它們可以是不連續(xù)的區(qū)間。

每一個(gè) Region 都可以根據(jù)需要,扮演新生代的 Eden 空間,Survivor 空間,或者老年代空間。除此之外它還有一類特殊的區(qū)域叫做 Humongous,專門(mén)用來(lái)存儲(chǔ)大對(duì)象。

上面說(shuō)的是啥意思呢?其實(shí)用圖片看起來(lái)就非常直觀了:

比如對(duì)于 CMS,使用的堆內(nèi)存結(jié)構(gòu)如下:

 

可以看到上面的圖片中不論是年輕代、老年代都是邏輯上連續(xù)的空間(但是不要求物理上的連續(xù))。

而G1的堆內(nèi)存被劃分為多個(gè)大小相等的 Region ,但是 Region 的總個(gè)數(shù)在 2048 個(gè)左右,默認(rèn)是 2048 。對(duì)于一個(gè) Region 來(lái)說(shuō),是邏輯連續(xù)的一段空間,其大小的取值范圍是 1MB 到 32MB 之間。

結(jié)構(gòu)如下:

 

圖片來(lái)源-文末資料4

上面的E、S和沒(méi)有寫(xiě)字母的藍(lán)色方塊(可以理解為old)沒(méi)啥說(shuō)的。

但是可以看到H是以往的垃圾收集器中沒(méi)有的概念,它代表 Humongous,這表示這些 Region 存儲(chǔ)的是巨型對(duì)象(humongous object,H-obj),當(dāng)新建對(duì)象大小超過(guò) Region 大小一半時(shí),直接在新的一個(gè)或多個(gè)連續(xù) Region 中分配,并標(biāo)記為H。

說(shuō)實(shí)話上面的這概念已經(jīng)“爛大街”了,任何一篇寫(xiě)G1都會(huì)聊到,包括本文也是。

沒(méi)辦法啊,朋友們,這是引子,必須得先聊幾句。就像斗地主,你第一手牌能直接出王炸嗎?不能啊,你不得先來(lái)一個(gè)對(duì)三,循序漸進(jìn)啊。

下面我送你一個(gè)小彩蛋吧。

注意到我上面說(shuō)的幾個(gè)數(shù)據(jù)了嗎,2048個(gè)左右,1MB到32MB,這些數(shù)據(jù)是哪里來(lái)的呢,我說(shuō)你就信了嗎?

很多文章聊到G1的時(shí)候都只是說(shuō)堆內(nèi)存被劃分為多個(gè)大小相等的 Region , Region 大小的取值范圍為 1MB 到 32MB ,但是并沒(méi)有提到 2048 這回事,我來(lái)給你尋根問(wèn)祖一下:

 

我找到的第一個(gè)數(shù)據(jù)來(lái)源于上面的這篇論文,即文末的資料4:

  • The goal is to have around 2048 regions for the total heap.

這篇論文的作者是Monica Beckwith,你可以去搜一下,她(是的,我沒(méi)打錯(cuò),是個(gè)妹子)擔(dān)任過(guò)Oracle G1 垃圾收集器性能團(tuán)隊(duì) Leader,權(quán)威吧。

第二個(gè)數(shù)據(jù)來(lái)源當(dāng)然是源碼了,更權(quán)威吧:

  • http://hg.openjdk.java.net/jdk/jdk/file/fa2f93f99dbc/src/hotspot/share/gc/g1/heapRegionBounds.hpp

 

知道這個(gè)2048重要嗎?我覺(jué)得不重要。

但是知道了就更牛逼呀!當(dāng)妹子聊到2048的時(shí)候她只知道這是一個(gè)游戲,你要告訴她這個(gè)數(shù)字也是G1的Region的默認(rèn)個(gè)數(shù)。

事了拂衣去,深藏功與名。

[[328457]]

 

G1的工作步驟

這一部分,也是耳熟能詳?shù)牟糠郑侨桃蝗?,馬上就要到你高呼:臥槽,牛逼的部分了。

眾所周知,一般我們說(shuō)G1的收集過(guò)程分為下面這四個(gè)步驟(下面四個(gè)步驟的描述來(lái)自于《深入理解Java虛擬機(jī)(第3版)》):

說(shuō)實(shí)在的,下面的描述確實(shí)看的讓人很懵逼的。面試的過(guò)程中問(wèn)到這一部分的時(shí)候,我相信大多數(shù)朋友都是硬背下來(lái)的。

所以,本文的目的就是為了讓你理解下面這幾個(gè)階段的具體過(guò)程。

這么說(shuō)吧,如果看完這篇文章你還是沒(méi)搞懂上面這幾個(gè)階段的話,那你再讀一遍。

再讀一遍,還是沒(méi)懂的話,那我這篇文章就算寫(xiě)失敗了。

初始標(biāo)記(Initial Marking):這階段僅僅只是標(biāo)記GC Roots能直接關(guān)聯(lián)到的對(duì)象并修改TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序并發(fā)運(yùn)行時(shí),能在正確的可用的Region中創(chuàng)建新對(duì)象,這階段需要停頓線程,但是耗時(shí)很短。

而且是借用進(jìn)行Minor GC的時(shí)候同步完成的,所以G1收集器在這個(gè)階段實(shí)際并沒(méi)有額外的停頓。

并發(fā)標(biāo)記(Concurrent Marking):從GC Roots開(kāi)始對(duì)堆的對(duì)象進(jìn)行可達(dá)性分析,遞歸掃描整個(gè)堆里的對(duì)象圖,找出存活的對(duì)象,這階段耗時(shí)較長(zhǎng),但是可以與用戶程序并發(fā)執(zhí)行。

當(dāng)對(duì)象圖掃描完成以后,還要重新處理SATB記錄下的在并發(fā)時(shí)有引用變動(dòng)的對(duì)象。

最終標(biāo)記(Final Marking):對(duì)用戶線程做另一個(gè)短暫的暫停,用于處理并發(fā)階段結(jié)束后仍遺留下來(lái)的最后那少量的 SATB 記錄。

篩選回收(Live Data Counting and Evacuation):負(fù)責(zé)更新 Region 的統(tǒng)計(jì)數(shù)據(jù),對(duì)各個(gè) Region 的回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶所期望的停頓時(shí)間來(lái)制定回收計(jì)劃。

可以自由選擇任意多個(gè) Region 構(gòu)成回收集,然后把決定回收的那一部分 Region 的存活對(duì)象復(fù)制到空的 Region 中,再清理掉整個(gè)舊 Region 的全部空間。

這里的操作涉及存活對(duì)象的移動(dòng),是必須暫停用戶線程,由多條收集器線程并行完成的。

上面雖然有4個(gè)階段,但是從上帝視角,我們可以把它分為兩大部分,或者說(shuō)從整個(gè)算法的角度,我們可以切分為兩大部分:

1.Global Concurrent Marking:全局并發(fā)標(biāo)記。

2.Evacuation Pauses:該階段是負(fù)責(zé)把一部分Region里的活對(duì)象拷貝到空Region里面去,然后回收原本的Region空間。

為什么我敢這樣去劃分呢?

一部分原因來(lái)自這篇論文中:

 

《Garbage-First Garbage Collection》這篇論文是 sun 實(shí)驗(yàn)室在 2004 年發(fā)布的第一篇關(guān)于 G1 的論文。夠權(quán)威吧?

該論文中,2.3小節(jié)就是介紹 Evacuation Pauses ,2.5小節(jié)就是介紹 Concurrent Marking ,下面是部分內(nèi)容截圖:

 

另一部分原因是 R大 也這樣說(shuō)的(見(jiàn)文末參考資料)。

接下來(lái),要回答讀者提出的問(wèn)題,我們就需要了解全局并發(fā)標(biāo)記階段。

全局并發(fā)標(biāo)記

這一節(jié)就是回答這個(gè)問(wèn)題:用戶線程執(zhí)行的時(shí)候不僅修改了對(duì)象引用關(guān)系,還新分配了新對(duì)象,G1 是如何找到并處理這些對(duì)象的呢?

要回答這個(gè)問(wèn)題,就涉及到 TAMS 了。前面我引用的書(shū)里說(shuō):

初始標(biāo)記(Initial Marking):這階段僅僅只是標(biāo)記 GC Roots 能直接關(guān)聯(lián)到的對(duì)象并修改 TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序并發(fā)運(yùn)行時(shí),能在正確的可用的 Region 中創(chuàng)建新對(duì)象。

這句話,每個(gè)字都能看懂,連在一起讀,也品出點(diǎn)兒味道,但是總感覺(jué)似懂非懂的樣子。

什么是 TAMS?什么是正確可用的 Region?新對(duì)象是創(chuàng)建在 Region 中的哪個(gè)位置的?

我們先從論文入手,我撿關(guān)鍵點(diǎn)給你說(shuō):

 

1.有兩個(gè) bitmap。

2.一個(gè)叫 previous,一個(gè)叫 next。

3.previous bitmap 是 concurrent marking 階段完成后的最后一個(gè) bitmap。(有點(diǎn)繞,后面會(huì)解釋)。

4.next bitmap 是當(dāng)前將要或正在進(jìn)行的 concurrent marking 的結(jié)果。

5.當(dāng)標(biāo)記完成后,兩個(gè) bitmap 會(huì)交換角色。

 

1.標(biāo)記周期的第一個(gè)階段就是清理 next bitmap。

2.然后,初始標(biāo)記階段 Stop The World(后面簡(jiǎn)稱STW),目的是標(biāo)記 GC Roots 能直接關(guān)聯(lián)到的對(duì)象。該階段借助 Minor GC 完成,沒(méi)有額外的停頓。

3.每個(gè) Region 包含兩個(gè) TAMS。

4.一個(gè)對(duì)應(yīng)前一輪標(biāo)記,一個(gè)對(duì)應(yīng)下一次標(biāo)記。

從論文中我們可以知道,G1的Concurrent Marking 用了兩個(gè) marking bitmap。

一個(gè) previous Bitmap 記錄的是上一輪 Concurrent Marking 后的對(duì)象標(biāo)記狀態(tài),因?yàn)樯弦惠喴呀?jīng)完成,所以這個(gè)bitmap的信息可以直接使用。

一個(gè) next Bitmap 記錄的是當(dāng)前這一輪 Concurrent Marking 的結(jié)果。這個(gè)bitmap是當(dāng)前將要或正在進(jìn)行的 Concurrent Marking 的結(jié)果,尚未完成,所以還不能使用。

我們可以假設(shè)一次并發(fā)標(biāo)記變成后的 Bitmap(previous Bitmap) 大概長(zhǎng)這樣:

 

白色地址之間是可以回收的對(duì)象,灰色地址之間是不可以回收的對(duì)象。

除了兩個(gè) bitmap 外,還有兩個(gè) TAMS(top at mark start)。每個(gè) Region 都有兩個(gè) TAMS,分別是 previous TAMS 和 next TAMS。

bitmap 和 TAMS 可以用下面的圖片來(lái)表示:

 

首先我們可以看到 bottom 和 top 之間是一個(gè) Region 已使用的部分。Top 到 end 之前是一個(gè) Region 未使用的部分。

另外可以看到上面我留了四個(gè)問(wèn)號(hào),接下我們的目的就是填補(bǔ)這些問(wèn)號(hào)。當(dāng)這些問(wèn)號(hào)被填上之后,所有的問(wèn)題都會(huì)迎刃而解。

兩個(gè) Bitmap 和兩個(gè) TAMS 是怎么工作的呢?

接下來(lái)按照:

  • 初始標(biāo)記(Initial Marking)
  • 并發(fā)標(biāo)記(Concurrent Marking)
  • 最終標(biāo)記(final marking,也叫Remark)
  • 清理階段(Cleanup)

這四個(gè)階段作圖說(shuō)明:

初始標(biāo)記(Initial Marking)

 

從圖片可以看到初始標(biāo)記階段 nextBitmap 是清空狀態(tài),沒(méi)有標(biāo)記任何存活的對(duì)象。

接著我們?cè)俅位氐綍?shū)中的描述里,我給你逐字描述清楚:

初始標(biāo)記(Initial Marking):這階段僅僅只是標(biāo)記 GC Roots 能直接關(guān)聯(lián)到的對(duì)象并修改 TAMS(Next Top at Mark Start)的值,讓下一階段用戶程序并發(fā)運(yùn)行時(shí),能在正確的可用的 Region 中創(chuàng)建新對(duì)象。

GC Roots 能直接關(guān)聯(lián)到的對(duì)象:就是一個(gè) Region 已經(jīng)使用過(guò)的部分,所以在 Bottom 與 top 之間。[勘誤見(jiàn)《面試官:你回去等通知吧!》]

修改 TAMS 的值:就是讓此時(shí)的 prevTAMS 指向 Bottom ,也就是一個(gè) Region 內(nèi)存地址起始值。讓此時(shí)的 nextTAMS 指向 Top。Top 實(shí)際上就是一個(gè) Region 未分配區(qū)域和已分配區(qū)域的分界點(diǎn)。

正確的可用的 Region :對(duì)一個(gè) Region 來(lái)說(shuō),當(dāng)上面的 nextBitmap 為空、4個(gè)指針都準(zhǔn)備就緒后,這個(gè) Region 在下一階段用戶程序并發(fā)運(yùn)行時(shí),就是一個(gè)正確的 Region。

下一階段用戶程序并發(fā)運(yùn)行時(shí),在正確的可用的 Region 中創(chuàng)建新對(duì)象是什么意思呢?

下一階段用戶程序并發(fā)運(yùn)行時(shí)指的就是并發(fā)標(biāo)記階段。

并發(fā)標(biāo)記(Concurrent Marking)

先看前面引用的書(shū)中描述:

并發(fā)標(biāo)記(Concurrent Marking):從 GC Roots 開(kāi)始對(duì)堆的對(duì)象進(jìn)行可達(dá)性分析,遞歸掃描整個(gè)堆里的對(duì)象圖,找出存活的對(duì)象,這階段耗時(shí)較長(zhǎng),但是可以與用戶程序并發(fā)執(zhí)行。當(dāng)對(duì)象圖掃描完成以后,還要重新處理 SATB 記錄下的在并發(fā)時(shí)有引用變動(dòng)的對(duì)象。

再看動(dòng)圖:

 

 

從 GC Roots 開(kāi)始對(duì)堆的對(duì)象進(jìn)行可達(dá)性分析,遞歸掃描整個(gè)堆里的對(duì)象圖,找出存活的對(duì)象:

意思就是說(shuō)在并發(fā)標(biāo)記階段, GC 線程工作在 prevTAMS 和 NextTAMS 之間,對(duì)堆里的對(duì)象進(jìn)行可達(dá)性分析(回想一下“三色標(biāo)記”),標(biāo)記完成后, NextBitmap 就有對(duì)應(yīng)有值了(里面放的是地址值),黑色對(duì)應(yīng)的是存活對(duì)象,白色對(duì)應(yīng)的垃圾對(duì)象。

這樣就找出存活對(duì)象了。

但是書(shū)中并沒(méi)有提及用戶線程分配對(duì)象的情況。所以讀者提出的問(wèn)題,在書(shū)中也找不到明確的答案。

答案就是: NextTAMS 與 Top 之間的對(duì)象,就是本次并發(fā)標(biāo)記階段用戶線程新分配的對(duì)象,它們是隱式存活的。

為什么這么說(shuō)?你去品一品論文里面我框起來(lái)的這句話。

 

但是面試官想要的是這一句話的答案嗎?不是的。

你聽(tīng)到這個(gè)問(wèn)題后,你先微微一皺眉,做出沉思狀,然后輕輕說(shuō)說(shuō)一句:這個(gè)問(wèn)題問(wèn)的很好,我先組織一下語(yǔ)言。(先舔他一波)

[[328459]]

 

然后你按照階段把圖畫(huà)出來(lái),指著給他講 TAMS 和 Bitmap 是怎么工作的。

另外,關(guān)于 NextTAMS 與 Top 為什么是重疊的,也得補(bǔ)充說(shuō)明一下:并發(fā)標(biāo)記的前一個(gè)階段是初始標(biāo)記。由于初始標(biāo)記是 STW 的,所以從動(dòng)圖中我們可以看到:并發(fā)標(biāo)記開(kāi)始,即初始標(biāo)記結(jié)束的時(shí)候, NextTAMS 與 Top 是重疊的。

隨著并發(fā)標(biāo)記過(guò)程的進(jìn)行, NextBitmap 被填充上了值。而 NextTAMS 與 Top 之間的區(qū)域越來(lái)越大,這就是用戶線程在并發(fā)標(biāo)記階段分配的新對(duì)象。

同時(shí)通過(guò)下面的圖我們可以看到, GC 線程的工作區(qū)間和用戶線程的工作區(qū)間是有重疊的(用工作區(qū)間這個(gè)概念去理解其中的一些細(xì)節(jié)不一定正確,但是可以這樣抽象的認(rèn)為,方便理解)。

 

而重疊的部分,就是可能產(chǎn)生“對(duì)象消失”的部分。對(duì)G1來(lái)說(shuō),就是原始快照(STAB)加寫(xiě)前屏障(Pre-Wirte Barrier)工作的部分。

所以這就是書(shū)里為什么說(shuō):當(dāng) GC 線程掃描完對(duì)象圖后,還需要重新處理 STAB 記錄下的在并發(fā)時(shí)有引用變動(dòng)的對(duì)象。

最終標(biāo)記(Remark)

書(shū)中是這樣的寫(xiě)的:

最終標(biāo)記(Final Marking):對(duì)用戶線程做另一個(gè)短暫的暫停,用于處理并發(fā)階段結(jié)束后仍遺留下來(lái)的最后那少量的 SATB 記錄。

最終標(biāo)記階段,由于是 STW 的,所以該階段對(duì)應(yīng)的圖是并發(fā)標(biāo)記階段完成后的圖,如下:

 

處理并發(fā)階段結(jié)束后仍遺留下來(lái)的最后那少量的 SATB 記錄是什么意思呢?

你想,并發(fā)標(biāo)記階段, GC 線程完成對(duì)象圖的掃描之后,還會(huì)去處理 SATB 記錄下的在并發(fā)時(shí)有引用變動(dòng)的對(duì)象。

在處理 SATB 記錄的數(shù)據(jù)的時(shí)候,由于用戶線程可能還是在繼續(xù)修改對(duì)象圖,繼續(xù)在產(chǎn)生 SATB 數(shù)據(jù),所以還是會(huì)有一小部分的 SATB 數(shù)據(jù),所以才需要一個(gè)短暫的暫停。

清理階段(Cleanup)

書(shū)里寫(xiě)的是篩選回收階段。其實(shí)就包含了清理階段和回收階段。這里我們只討論清理階段,不討論回收。

在這個(gè)階段, NextBitmap 和 PrevBitmap 會(huì)交換位置:

 

所以,我們的圖就變成了下面的樣子:

 

可以看到,NextBitmap 和 PrevBitmap 交換了位置,NextTAMS 和 PrevTAMS 交換了位置。

而 Region 中, Bitmap 白色部分對(duì)應(yīng)的已使用內(nèi)存變成了淺灰色。它僅僅是標(biāo)記了出來(lái),并沒(méi)有進(jìn)行清掃操作。

需要注意的是:清理階段不拷貝任何對(duì)象

引用R大的回答來(lái)描述這個(gè)階段:

清點(diǎn)和重置標(biāo)記狀態(tài)。這個(gè)階段有點(diǎn)像 mark-sweep 中的 sweep 階段,不過(guò)不是在堆上 sweep 實(shí)際對(duì)象,而是在 marking bitmap 里統(tǒng)計(jì)每個(gè) Region 被標(biāo)記為活的對(duì)象有多少。這個(gè)階段如果發(fā)現(xiàn)完全沒(méi)有活對(duì)象的 Region 就會(huì)將其整體回收到可分配 Region 列表中。

好了,到這里我們就能把前面的那張圖給填上了:

 

然后再看一下論文中的這張圖片,你就會(huì)發(fā)現(xiàn),我上面的過(guò)程都是基于這張圖片去分析的,圖中展示了兩個(gè)循環(huán), A-B-C , D-E-F 。其中 E、F 過(guò)程就是 B、C 過(guò)程的重復(fù):

 

我讓上面的圖片動(dòng)起來(lái),請(qǐng)你細(xì)細(xì)品。

請(qǐng)注意各個(gè)階段 PrevTAMS 、 NextTAMS 指針的交換、 PrevBitmap 和 NextBitmap 位置的交換:

 

如果一次看不懂,就再看一次??吹臅r(shí)候結(jié)合上面的長(zhǎng)圖和動(dòng)圖一起分析,效果更佳。

 

參考資料:

1.https://max.book118.com/html/2018/0815/7043143036001143.shtm

2.https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html

3.https://www.oracle.com/technetwork/java/javase/tech/g1-intro-jsp-135488.html

4.https://www.infoq.com/articles/G1-One-Garbage-Collector-To-Rule-Them-All/

5.https://hllvm-group.iteye.com/group/topic/44381

6.《深入理解Java虛擬機(jī)(第三版)》

本文轉(zhuǎn)載自微信公眾號(hào)「 why技術(shù)」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系 why技術(shù)公眾號(hào)。

 

責(zé)任編輯:武曉燕 來(lái)源: why技術(shù)
相關(guān)推薦

2009-08-14 08:56:49

Java垃圾回收器G1

2009-07-24 09:41:45

Java 7 G1垃圾回收器

2024-12-03 09:01:33

2022-02-25 08:01:34

CMS

2024-10-22 16:26:11

2009-06-02 10:18:43

Java垃圾回收器垃圾回收器Java垃圾回收

2023-11-16 08:00:56

Java11G1

2021-03-11 07:26:52

垃圾回收器單線程

2021-08-10 07:00:02

Java8 G1垃圾回收器

2009-06-18 13:59:33

Java SE 6垃圾回收器

2019-08-26 10:36:22

6G5G網(wǎng)絡(luò)

2021-08-15 18:59:13

垃圾收集器JDK

2023-02-20 15:28:18

2024-10-28 13:18:54

2015-06-17 14:10:52

OracleJava 9垃圾收集器

2022-03-21 11:33:11

JVM垃圾回收器垃圾回收算法

2022-06-27 16:55:30

5G6G

2022-01-20 10:34:49

JVM垃圾回收算法

2017-08-04 10:53:30

回收算法JVM垃圾回收器

2022-07-27 08:01:29

CMS垃圾回收器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)