面試官看了我以前的文章對我說:你回去等通知吧!

這是why技術的第37篇原創文章web

老規矩,先聊聊生活,上面這張圖片是我週一拍的。面試

週一夜下班後發現公司樓下推着三輪車賣花的阿姨又開始賣花了。整個路口只有她一我的在作生意,整條路上也沒有幾個行人,你們都低着頭匆匆走着,繁花中帶着點憂傷。併發

因而,我去買了一把白玫瑰。jvm

上週日把《霍亂時期的愛情》看完了,就恰好當道具拍了上面的照片。整體來講我不喜歡這種縱情聲色的故事,更不喜歡那個看起來堂而皇之的理由∶「我一輩子有622個情人,可是我只愛過你」。雖然它真的是窮極了愛情的全部可能性,可是它不夠真實。編輯器

相比之下我以爲錢鍾書先生寫的《圍城》∶「我說的讓她三分,不是三分流水七分塵的三分,而是天下明月只有三分的三分。」這樣打打鬧鬧的愛情更加真實。post

再看楊絳先生的《咱們仨》,書的最後她說∶「世間好物不堅牢,彩雲易散琉璃脆」。這纔是愛情,這纔是真實的生活。學習

好了,說迴文章。spa

對不起,我錯了。

前面發的這兩篇文章:線程

《面試官:你說你熟悉jvm?那你講一下併發的可達性分析》3d

《面試官:G1回收器怎麼知道你是何時的垃圾?》

裏面有一些沒有說清楚的地方,又有不少讀者來問,因此我以爲須要補充說明一下

更重要的是,通過高手指點,其中還有一些描述錯誤的地方,我也須要進行勘誤

若是真的是面試題,可能面試官就會對我說:好了,咱們今天就先到這裏。你回去等通知吧。

若是你沒看過我剛剛說的兩篇文章,我建議你不要看這篇,由於一看就得看三篇,若是裏面的衍生知識點你還想完全弄明白,一個下午就過去了......(固然,你看了後收穫確定仍是有的。)

若是你看了我以前的兩篇文章,我求求你必定看看這篇,補充、更正一下答案,等面試官真的問起細節來,也不怕......

好了,在閱讀本文以前,我假設你已經讀過我前面說的兩篇優質、幽默、有料的文章了。

併發的可達性分析-勘誤

以前發佈了這篇文章《面試官:你說你熟悉jvm?那你講一下併發的可達性分析》,對於文中這一部份內容中的動圖,有不少朋友給我說看不懂:

我把這個動圖拿出來:

首先,須要說明的是,我如今也看不懂這個動圖了。(畫錯了就是畫錯了,還強行找個理由)。

接下來,忘記這個動圖,咱們從新分析一波原始快照方案(如下簡稱SATB,Snapshot At The Beginning)。

首先,咱們看初始標記階段(即根節點枚舉)完成後,剛剛進入併發標記階段,GC 線程開始掃描時的對象圖:

在上面這張圖裏,當GC Roots肯定後,對象圖就已經肯定了。SATB掃描的時候基於已經肯定的對象圖(快照版的對象圖)掃描,也就是說掃描過程當中上面的快照圖的引用關係是不會發生變化的,可是真實的對象圖是會發生變化的。

舉個例子:就相似於你在操場上拍了一張照片,你數照片裏面的人數,照片是不會發生變化,人數一直都是這麼多,可是真實的操場上的人是在時刻變化的。

因此,在對象圖肯定的一刻,正常掃描完成後,對象圖變成了下面這樣:

好了,面前的鋪墊完成了。

咱們這裏須要演示的是「對象消失」狀況。

首先,咱們先肯定一下上面展現的對象圖,在併發標記階段必然有一個時刻的對象圖是這樣的:

咱們基於這個時刻的這個對象圖去討論「對象消失」的問題。

還得記得"對象消失"必須同時知足的兩個條件嗎?(這兩個條件是摘抄自《深刻理解Java虛擬機(第3版)》P.89)

條件一:賦值器插入了一條或者多條從黑色對象到白色對象的新引用。

條件二:賦值器刪除了所有從灰色對象到該白色對象的直接或間接引用。

咱們再仔細的讀一遍第二個條件,你會發現,它說的是**「該白色對象」。這個「該白色對象」指的是條件一里面的白色對象。**

因此,咱們有理由相信:條件一和條件二是有前後順序的,即必須是賦值器插入了一條或者多條從黑色對象到白色對象的新引用,而後賦值器又刪除了所有從灰色對象到該白色對象的直接或間接引用。在這樣的狀況下,纔會出現「對象消失」的狀況。

通過高人指點,咱們還能夠進行反證法,以下:

咱們假設灰色對象到白色對象的引用先刪除了,即先觸發了條件二。那麼對應的這個時刻真實的對象圖將變成下面的樣子:

(注意我這裏強調的是真實的對象圖,而不是快照的對象圖。再次重申:快照的對象圖在掃描開始的時候就肯定了,掃描過程當中是不會變化的。)

那麼,白色對象9是處於遊離態的,從根節點沒有任何引用鏈相連,用圖論的話來講就是從 GC Root 到對象9不可達,則證實此對象是不可能再被使用的。所以用戶線程不可能把黑色對象5指向遊離態的白色對象9,你寫不出這樣的代碼來。

若是說上面的圖你一眼沒看出來,那麼請看下面這圖,是否是恍然大悟:

黑色對象5不能指向白色對象9,那麼第一條規則就知足不了了。

因此,綜上咱們能夠得出:條件一和條件二是有前後順序的。

那麼咱們根據條件一繼續作圖以下:

條件一是賦值器插入了一條或者多條從黑色對象到白色對象的新引用。

在上面這個圖的場景中,就是 GC 線程在工做的同時,賦值器插入了一條黑色對象5到白色對象9之間的新引用。(用紅色線條以示區分)

在這個時刻,因爲灰色對象6指向白色對象9,因此黑色對象5能夠指向白色對象9,想想咱們前面的證實,只要有引用鏈,黑色對象就能夠到達白色對象。

這個時候僅僅知足了條件一,對象還沒消失。

接下來就是條件二的圖,STAB破壞的就是條件二

條件二是賦值器刪除了所有從灰色對象到該白色對象的直接或間接引用

在上面這個圖的場景中,就是賦值器刪除了灰色對象6到白色對象9的直接引用。

這個時候白色對象9就是「消失的對象」了,由於黑色的對象5是不會被再次掃描的。

須要注意的是,賦值器能夠理解爲用戶線程,因爲在併發標記階段,用戶線程和 GC 線程在同時運行,因此須要出現上面的圖,還有一個前置條件就是:

用戶線程刪除對象6到對象9之間的引用,要先於 GC 線程掃描到對象6,把對象6變成灰色的操做。由於只有這樣,GC 線程處理到對象6的時候,纔有對應的寫屏障記錄。

若是在 GC 線程已經掃描過對象6,即對象6已是黑色的狀況下(這個時候對象9,不是黑色就是灰色,不多是白色),用戶線程再去刪除對象6到對象9之間的引用,GC 線程是不須要處理的,由於對象9已是非白了,它在本輪中一定會活下來。

這裏我引用R大的描述:

https://hllvm-group.iteye.com/group/topic/44381?page=2

由於刪除操做會觸發 pre-write barrier,把每次引用關係變化時舊的引用值記下來,只有這樣,等 GC 線程到達某一個對象時,這個對象的全部引用類型字段的變化全都有記錄在案,就不會漏掉任何在快照圖裏活的對象。固然,極可能有對象在快照中是活的,但隨着併發 GC 的進行它可能原本已經死了,但 SATB 仍是會讓它活過此次 GC,變成了浮動垃圾。

SATB 在寫屏障裏,把舊的引用所指向的對象都變成非白的(已經黑灰就不用管,仍是白的就變成灰的)。

這樣作的實際效果是:若是一個灰對象的字段本來指向一個白對象,但在concurrent marker能掃描到這個字段以前,這個字段被賦上了別的值(例如說null),那麼這個字段跟白對象之間的關聯就被切斷了。SATB write barrier保證在這種切斷髮生以前就把字段本來引用的對象變灰,從而杜絕了上述條件二的發生。

其中:「把舊的引用所指向的對象都變成非白的。」在咱們這個場景下含義以下:

舊的引用指的是:灰色對象6到白色對象9之間的引用。

所指向的對象指的是:白色對象9。

都變成非白的:指的是白色對象9變成了灰色。

因此,在兩個條件順序觸發、對象圖掃描完成後會變成下面的樣子:

併發掃描結束以後,再以灰色對象9爲根(把它做爲根,天然會變成黑色),從新掃描一次,因此最終的對象圖變成了這樣:

有的小夥伴就會問了:若是在標記過程當中,用戶線程並無把對象5指向對象9的操做,僅僅是發生了刪除對象6到對象9之間引用的操做,那麼這個對象圖是什麼樣子呢?

就是下面這個樣子,你應該能夠想象出來:

對象9仍是黑色,只是它變成了浮動垃圾,逃過了本次回收而已。並不影響程序運行。

接下來,讓上面的圖動起來,而且我把圖片之間的切換順序放慢。你再本身細品品:

因此,上面的所有描述,纔是一次我認爲正確的,展現SATB方案是如何解決「對象消失」問題的過程。

以前《面試官:你說你熟悉jvm?那你講一下併發的可達性分析》中對於這一部分的描述過於簡單,且存在錯誤,給你們道歉,並特以此文進行修正。

你是何時的垃圾-勘誤

在《G1回收器:我怎麼知道你是何時的垃圾?》這篇文章中有一句描述是這樣的:

「GC Roots 能直接關聯到的對象:就是一個 Region 已經使用過的部分,因此在 bottom 與 top 之間。」這句話是錯誤的。

實際上,經過文章後面的描述你也能發現。GC Roots 能直接關聯到的對象集合應該「小於」 Region 已經使用過的部分,對象圖遞歸完以後,全部對象總和,纔等於Region已經使用過的部分。

經過文章中後半部分的這個圖片也能夠直觀的發現, bottom 到 top 之間是一個 Region 已經使用的部分。可是這一部分中,只有 bottom 到 NextTAMS 之間的對象纔是 GC Roots 能直接關聯到的對象,這部分對象並非一個 Region 已經使用過的部分。

你是何時的垃圾-補充說明

關於《G1回收器:我怎麼知道你是何時的垃圾?》這篇文章,還有兩個須要補充說明的地方。

有的讀者問說:文章中沒有討論回收的內容,每次清理不會真正回收,那是否是多輪標記後才發生一次回收呢?

一。

首先,文章中確實沒有討論回收相關的內容。我在前面部分也寫了,把G1回收切分爲兩大部分:

1.Global Concurrent Marking:全局併發標記。

2.Evacuation Pauses:該階段是負責把一部分Region裏的活對象拷貝到空Region裏面去,而後回收本來的Region空間。

只要清楚了全局併發標記階段,就能夠解答文中拋出的這個問題:

因此我只說明了全局併發標記階段。

若是想要了解回收階段的事,能夠去看看R大的回答,強烈建議你看完本文,點個贊後,打開下面的連接,反覆閱讀幾遍:

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

其次,「每次清理不會真正回收,那是否是多輪標記後才發生一次回收呢?」

這句話,多是我在文章強調了清理階段不拷貝任何對象,再加上沒有描述回收階段,致使讀者有點懵了吧。

一次全局併發標記完成後,緊接着一次回收的過程。

只是G1收集器之因此能創建可預測的停頓時間模型(-XX:MaxGCPauseMillis指定,默認值爲200毫秒),是由於它將 Region 做爲單次回收的最小單元,即每次收集到的內存空間都是 Region 大小的整數倍,這樣就能夠有計劃地避免在整個Java堆中進行全區域的垃圾回收。

更具體一點的作法就是每一個 Region 裏面堆積的垃圾都有一個「價值」(價值即回收所得到的空間大小以及回收所須要的時間的經驗值)。而這些「價值」,是維護在一個優先級列表中的,G1收集器都是知道的。

因此回收階段會優先處理回收價值最大的那些 Region。所以,一次回收的過程並不會回收全部的 Region。

二。

這裏也就解釋了讀者提出的另一個問題:若是每次標記完都會回收整理,那爲何紅框所在的區間與上一次標記以後相同,好像沒有被整理同樣,整理以後不是應該不留下內存空隙嗎?

我以爲一個合理的解釋,就是我上面說的:這個 Region 的價值不夠,因此它本次沒有被回收。隨着時間的推移,它裏面堆積的垃圾愈來愈多,「價值」就愈來愈高,老是會被回收的。

還有讀者問:看了併發標記的過程,有個疑問 prevBitmap 的做用是什麼? 由於感受每次都是從頭開始掃描,沒看到它的做用。

這個問題,能夠從這張圖片入手解答:

這個 E 是 Remark 階段,能夠看到,在這個階段,其實 PrevBitmap 是派上用場了。

前面剛剛說了,這個 Region 因爲「價值」不夠,它逃過了上次垃圾回收,因此待到下次垃圾回收的時候,就是 prevBitmap 的用武之地了,它裏面記錄的地址對應的區間就不須要再次標記了,由於這些地址對應的對象就已是垃圾了。

咱們能夠假設 E 表明的是第 n 輪迴收的過程的Remark階段。那麼 PrevBitmap 就是第 n-1 輪的標記結果。

以前的文章說了:一個 previous Bitmap 記錄的是上一輪 Concurrent Marking 後的對象標記狀態,由於上一輪已經完成(上一輪就是第n-1輪),因此這個bitmap的信息能夠直接使用。

能夠直接使用的意思就是前面說的:它裏面記錄的地址對應的區間就不須要再次標記了,由於這些地址對應的對象就已是垃圾了。

到 F 圖裏面,能夠看到,當前的 F 圖是清理階段已經完成的狀態了:

判斷標準有二:

1.和 E 圖相比PrevBitmap 和 NextBitmap 已經交換了位置。

2.PrevBitmap 裏面對應的地址的空間已經被標記爲淺灰色了。

這個時候已經完成標記,PrevBitmap 又變成了第n-1次標記的結果。

你是什麼垃圾-懟人

由於以前的文章已經發布了,因此我須要修改一下對應的內容。提醒後面的讀者,若是看到了文章,須要注意這些地方描述的有問題。

可是我在查找我文章的過程當中發現了一些讓我很鬱悶的事情,以前的文章,大都被剽竊了,我也見怪不怪,有時間就順手舉報一下了。

最過度的是下面這個:

這是一個百家號帳號,一字不差的抄我文章,還本身標註爲「原創」?

我去寫了個評論:

他還不敢把評論放出來。

還有下面這個,你可長點心吧。你配的這張圖片,我卻是想在家拍,可是我拍不出來呀:

這樣的狀況還有不少。說到底,就仍是版權意識的問題。

版權問題,我以前在《訂閱號作了77天,我掙了487.52元》這篇文章裏面聊過:

個人號不會傳播任何盜版資源,之前如此,如今如此,之後也會如此。

不作惡,就是最大的善。與君共勉。

因此我在此鄭重聲明,若是未經許可轉載個人文章,必須標明原文地址,且保留文末公衆號二維碼,不然我必定見一個舉報一個。

我先舉報你涉黃,引發工做人員的注意,再舉報你抄襲,讓工做人員懲罰你。

氣死我了。

最後說一句(求關注)

經過這件事我也再次感受到了,看網上的野生文章(好比個人),要持有謹慎、懷疑、學習的態度。

才疏學淺,不免會有紕漏,若是你發現了錯誤的地方,還請你留言給我指出來,我對其加以修改。(我每篇技術文章都有這句話,我是認真的說的。)

感謝您的閱讀,我堅持原創,十分歡迎並感謝您的關注。

我是why技術,一個不是大佬,可是喜歡分享,又暖又有料的四川好男人。

以上。

歡迎關注公衆號【why技術】,堅持輸出原創。分享技術、品味生活,願你我共同進步。

相關文章
相關標籤/搜索