難道現(xiàn)在已經(jīng)卷到需要問三色標(biāo)記了嗎?

曾經(jīng)栋荸,我以為這些東西自己平時看看書就夠了菇怀,屬于那種花了半天精力總算搞明白了,然后過兩天就自然忘記的東西晌块。

結(jié)果爱沟,這都啥啊,啥是卡表匆背,什么又是三色標(biāo)記法呼伸,這些鬼問題都有人面試問,卷就完了。

引用計數(shù)&可達性分析

要進行垃圾回收GC括享,那么我們首先就要決定到底怎么判斷對象是否存活搂根?一般來說有兩種方式。

引用計數(shù)铃辖,給對象添加一個計數(shù)器剩愧,每當(dāng)有地方引用它計數(shù)器就+1,反之引用失效時就-1联逻,那么計數(shù)器值為0的對象就是可以回收的對象从祝,但是有一個問題就是循環(huán)引用的話無法解決弃酌。

對于現(xiàn)在的虛擬機來說,主要用的算法是可達性分析算法锦积。

首先定義GC ROOTS根對象集合,通過GC ROOTS向下搜索瓶殃,搜索的過程走過的路徑稱作引用鏈充包,如果某個對象到GC ROOTS沒有任何引用鏈,那么就是對象不可達遥椿,是可以被回收的對象基矮。

不可達對象需要進行兩次標(biāo)記,第一次發(fā)現(xiàn)沒有引用鏈相連冠场,會被第一次標(biāo)記家浇,如果需要執(zhí)行finalize()方法,之后這個對象會被放進隊列中等待執(zhí)行finalize()碴裙,如果在finalize()中成功和引用鏈上的其他對象關(guān)聯(lián)钢悲,就會被移出可回收對象集合。(但是不建議使用finalize()方法)

分代收集

有了如何判斷對象存活的基礎(chǔ)舔株,接下來的問題就是怎么進行垃圾收集GC莺琳,現(xiàn)在商用的虛擬機基本上都是分代收集的實現(xiàn),它的實現(xiàn)建立于兩個假說:

  1. 絕大多數(shù)對象都是朝生夕死的
  2. 熬過越多次垃圾回收的對象越難死亡

基于這兩個假說载慈,就產(chǎn)生了現(xiàn)在我們常見的年輕代和老年代惭等。

因為分代了,所以GC也就分代了办铡。

年輕代用于存放那些死的快的對象辞做,年輕代GC我們稱之為MinorGC,每次年輕代內(nèi)存不夠我們就觸發(fā)MinorGC寡具,以后還有存活的對象我們就根據(jù)經(jīng)歷過MinorGC次數(shù)和動態(tài)年齡判斷來決定是否晉升老年代秤茅。

老年代則存放老不死的對象,這里GC稱之為OldGC童叠,現(xiàn)在也有很多人把他叫做FullGC框喳,實際上這并不準(zhǔn)確,F(xiàn)ullGC應(yīng)該泛指年輕代和老年代的的GC。

按照我們上文所說的使用可達性分析算法來判斷對象的存活帖努,那么假如我們進行MinorGC撰豺,會不會有對象被老年代引用著?進行OldGC會不會又有對象被年輕代引用著拼余?
如果是的話污桦,那我們進行MinorGC的時候不光要管GC Roots,還有再去遍歷老年代匙监,這個性能問題就很大了凡橱。

因此,又來了一個假說亭姥。稼钩。。

跨代引用相對于同代引用來說僅占極少數(shù)达罗。

由此就產(chǎn)生了一個新的解決方案坝撑,我們不用去掃描整個老年代了,只要在年輕代建立一個數(shù)據(jù)結(jié)構(gòu)粮揉,叫做記憶集Remembered Set巡李,他把老年代劃分為N個區(qū)域,標(biāo)志出哪個區(qū)域會存在跨代引用扶认。

以后在進行MinorGC的時候侨拦,只要把這些包含了跨代引用的內(nèi)存區(qū)域加入GC Roots一起掃描就行了。

image

卡表

說完這些辐宾,才到了第一個話題:卡表狱从。

卡表實際上就是記憶集的一種實現(xiàn)方式,如果說記憶集是接口的話叠纹,那么卡表就是他的實現(xiàn)類季研。

對于HotSpot虛擬機來說,卡表的實現(xiàn)方式就是一個字節(jié)數(shù)組誉察。

CARD_TABLE [this address >> 9] = 0;

這段代碼代表著卡表標(biāo)記的的邏輯与涡。實際上卡表就是映射了一塊塊的內(nèi)存地址,這些內(nèi)存地址塊稱為卡頁冒窍,從代碼可以看出每個卡頁的大小就是2^9=512字節(jié)。

如果轉(zhuǎn)換為16進制豺鼻,數(shù)組的0综液,1號元素就映射為0x0000~0x01FF(0-511)、0x0200~0x03FF(512-1023)內(nèi)存地址的卡頁儒飒。


image

只要一個卡頁內(nèi)的對象存在一個或者多個跨代對象指針谬莹,就將該位置的卡表數(shù)組元素修改為1,表示這個位置為臟,沒有則為0附帽。

在GC的時候埠戳,就直接把值為1對應(yīng)的卡頁對象指針加入GC Roots一起掃描即可。

有了卡表蕉扮,我們就不需要去在發(fā)生MinorGC的時候掃描整個老年代了整胃,性能得到了極大的提升。

卡表的問題

寫屏障

卡表的數(shù)組元素要修改成1喳钟,也就是臟的狀態(tài)屁使,對于HotSpot來說是通過寫屏障來實現(xiàn)的,實際上就是在其他分代引用了當(dāng)前分代的對象時候奔则,在對引用進行賦值的時候進行更新蛮寂,更新的方式類似AOP的切面思想。

void oop_field_store(oop* field, oop new_value) { 
// 引用字段賦值操作
*field = new_value;
// 寫后屏障易茬,在這里完成卡表狀態(tài)更新 
post_write_barrier(field, new_value);
}

寫屏障帶來的問題就是額外的性能開銷酬蹋,不過這個問題不大,還能接受抽莱。

偽共享

緩存行通常來說都是64字節(jié)范抓,一個卡表元素1個字節(jié),占用的卡頁內(nèi)存大小就是64*512=32KB的大小岸蜗。

如果多線程剛好更新剛好處于這32KB范圍內(nèi)的對象尉咕,那么就會對性能產(chǎn)生影響。

怎么解決偽共享問題璃岳?

JDK7之后新增了一個參數(shù)-XX:+UseCondCardMark年缎,他代表是否開啟卡表更新的判斷,沒有被標(biāo)記過才標(biāo)記為臟铃慷。

if (CARD_TABLE [this address >> 9] != 0) 
    CARD_TABLE [this address >> 9] = 0;

三色標(biāo)記法

卡表解決了跨代收集和根節(jié)點枚舉的性能問題单芜。而有了這些措施實際上枚舉根節(jié)點這個過程造成的STW停頓已經(jīng)屬于可控范圍。

另外還存在一個問題就是接下來從GC Roots開始遍歷犁柜,怎么才能高效的標(biāo)記這些對象洲鸠,這就是三色標(biāo)記法的作用了。因為如果堆內(nèi)的對象越多馋缅,那么顯然標(biāo)記產(chǎn)生的停頓時間就越長扒腕。

以現(xiàn)在我們熟知的CMS或者G1來舉例,GC的前兩個步驟如下:

  1. 初始標(biāo)記:標(biāo)記GC ROOT能關(guān)聯(lián)到的對象萤悴,這一步需要STW瘾腰,但是停頓的時間很短。
  2. 并發(fā)標(biāo)記:從GCRoots的直接關(guān)聯(lián)對象開始遍歷整個對象圖的過程覆履,這個時間會比較長蹋盆,但是現(xiàn)在是可以和用戶線程并發(fā)執(zhí)行的费薄,這個效率的問題就是三色標(biāo)記關(guān)注的問題。

在三色標(biāo)記法中栖雾,把從GC Roots開始遍歷的對象標(biāo)記為以下三種顏色:

  1. 白色楞抡,在剛開始遍歷的時候,所有的對象都是白色的
  2. 灰色析藕,被垃圾回收器掃描過召廷,但是至少還有一個引用沒有被掃描
  3. 黑色,被垃圾回收器掃描過噪径,并且這個對象的引用也全部都被掃描過柱恤,是安全存活的對象

整個標(biāo)記的過程如下,首先剛開始從GC Roots開始遍歷的時候肯定所有的對象都是白色的找爱。


image

接著A\G對象被掃描到變成灰色梗顺,然后A\G對象的引用也都被掃描,A\G對象變成黑色车摄。

B\C對象開始被掃描變成灰色寺谤,他們的引用也被掃描完成后自己也就都變成了黑色。

而后D對象也一樣會經(jīng)歷從灰色到黑色的過程(偷點懶吮播,省略一張無關(guān)緊要的過程圖吧)

最后剩下的E\F節(jié)點就是可以被回收的對象了变屁。

三色標(biāo)記的問題

雖然三色標(biāo)記法很高效,但是也會引申出其他的問題意狠。

首先我們上文說過并發(fā)標(biāo)記的過程是不會STW的粟关,就是你媽在打掃衛(wèi)生,而你在旁邊一直丟垃圾环戈,這也沒關(guān)系闷板,大不了最后就是還有一些垃圾沒掃干凈而已。

對于三色標(biāo)記來說就是把應(yīng)該要清理的對象標(biāo)記成存活院塞,這樣本次GC就無法清理這個對象遮晚,這個被稱作為浮動垃圾,解決方案就是等下次GC的時候再清理拦止,這次掃不干凈就等你媽下次打掃衛(wèi)生的時候再清理就行了县遣。

與此相反,如果把存活對象標(biāo)記成需要清理汹族,那么就有點麻煩了萧求,這樣你的程序就該出問題了。

所以經(jīng)過研究表明顶瞒,只有同時滿足兩個條件才會發(fā)生這種對象消失的問題:

  1. 插入了一條或者多條黑色到白色對象的引用
  2. 刪除了全部從灰色到白色對象的引用

那么夸政,針對這個問題也有兩種解決方案:增量更新原始快照,如果對應(yīng)到垃圾回收器的話搁拙,CMS使用的是增量更新秒梳,而像G1則是使用原始快照。

思路就是既然要同時滿足箕速,那么我只需要破壞其中一個條件那么不就可以了嗎酪碘?

所以,先看上面我們的例子中的一個場景盐茎,假設(shè)A掃描完兴垦,剛好C成為灰色,此時C->D的引用刪除字柠,同時A->D新增了引用(同時滿足兩個條件了吧)探越,這樣本來按照順序接下來D應(yīng)該會變成黑色(黑色對象不應(yīng)該被清理),但是由于C->D沒有引用了窑业,A已經(jīng)成為了黑色對象钦幔,他不會再被重新掃描了,所以即便新增了A->D的引用常柄,D也只能成為白色對象鲤氢,最終被無情地清理。
[圖片上傳失敗...(image-ede014-1625575081690)]

增量更新解決方案就是西潘,他會把這些新插入的引用記錄下來卷玉,掃描結(jié)束之后,再以黑色對象為根重新掃描一次喷市。這樣看起來不就是增量更新嗎相种?新插入的記錄再掃一次!

原始快照則是去破壞第二個條件品姓,他把這個要刪除的引用記錄下來寝并,掃描結(jié)束之后,以灰色對象為根重新掃描一次缭黔。所以就像是快照一樣食茎,不管你刪沒刪,其實最終還是會按照之前的關(guān)系重新來一次馏谨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末别渔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惧互,更是在濱河造成了極大的恐慌哎媚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喊儡,死亡現(xiàn)場離奇詭異拨与,居然都是意外死亡,警方通過查閱死者的電腦和手機艾猜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門买喧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捻悯,“玉大人,你說我怎么就攤上這事淤毛〗窀浚” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵低淡,是天一觀的道長姓言。 經(jīng)常有香客問我,道長蔗蹋,這世上最難降的妖魔是什么何荚? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮猪杭,結(jié)果婚禮上餐塘,老公的妹妹穿的比我還像新娘。我一直安慰自己皂吮,他們只是感情好唠倦,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涮较,像睡著了一般稠鼻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狂票,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天候齿,我揣著相機與錄音,去河邊找鬼闺属。 笑死慌盯,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的掂器。 我是一名探鬼主播亚皂,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼国瓮!你這毒婦竟也來了灭必?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤乃摹,失蹤者是張志新(化名)和其女友劉穎禁漓,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孵睬,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡播歼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了掰读。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秘狞。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡叭莫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出烁试,到底是詐尸還是另有隱情食寡,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布廓潜,位于F島的核電站,受9級特大地震影響善榛,放射性物質(zhì)發(fā)生泄漏辩蛋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一移盆、第九天 我趴在偏房一處隱蔽的房頂上張望悼院。 院中可真熱鬧,春花似錦咒循、人聲如沸据途。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裆蒸。三九已至,卻和暖如春佛致,著一層夾襖步出監(jiān)牢的瞬間辙谜,已是汗流浹背装哆。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工蜕琴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人梗夸。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓辛块,卻偏偏與公主長得像铅碍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子尘盼,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

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