深入理解Java虛擬機(jī)(四)—— GC算法細(xì)節(jié)實(shí)現(xiàn)

? ? ? ? 前面的章節(jié)了解到虛擬機(jī)的對(duì)象存活判定和垃圾回收基礎(chǔ)理論恨诱,但是具體如何實(shí)現(xiàn)才能保證虛擬機(jī)的高效運(yùn)行就不得不依托于嚴(yán)格的算法媳瞪。

一、 根節(jié)點(diǎn)枚舉

? ? ? ? 可達(dá)性分析算法從GC ROOTS找出引用鏈為例照宝,可作為GC ROOTS的節(jié)點(diǎn)主要在全局性的引用(常量蛇受、類靜態(tài)屬性)與執(zhí)行上下文(棧幀中的本地變量表)中,盡管目標(biāo)明確厕鹃,但是在方法區(qū)過(guò)大時(shí)兢仰,高效查找并不是一件簡(jiǎn)單的事。

? ? ? ? 目前剂碴,所有收集器在根節(jié)點(diǎn)枚舉時(shí)把将,都必須暫停用戶線程。

? ? ????根節(jié)點(diǎn)枚舉最長(zhǎng)的引用鏈可以做到與用戶線程一起并發(fā)忆矛,要確保枚舉期間對(duì)象的引用關(guān)系不會(huì)不斷的發(fā)生變化察蹲,枚舉根節(jié)點(diǎn)時(shí)暫停用戶線程是必要的。即便是CMS催训、G1等收集器也不例外递览。

????????當(dāng)用戶線程暫停后,其實(shí)并不需要一個(gè)不漏的檢查所有的執(zhí)行上下文和全局的引用位置瞳腌,虛擬機(jī)應(yīng)該是有辦法直接得到哪些地方存放著對(duì)象引用的,HotSpot使用被稱為OopMap的數(shù)據(jù)結(jié)構(gòu)來(lái)做優(yōu)化镜雨,當(dāng)類加載完成時(shí)嫂侍,虛擬機(jī)就會(huì)把對(duì)象內(nèi)偏移量對(duì)應(yīng)的數(shù)據(jù)類型計(jì)算出來(lái),在編譯期也會(huì)在特定位置記錄棧和寄存器里引用的位置荚坞,因此挑宠,垃圾收集器在掃描時(shí)可以直接得到這些信息,而不需要一個(gè)不漏的從方法區(qū)的根節(jié)點(diǎn)開(kāi)始尋找颓影,如下:

圖 1-1 String.HashCode?

二各淀、安全點(diǎn)

? ? ? ? OopMap結(jié)構(gòu)的引入,高效的完成GC ROOTS枚舉的同時(shí)诡挂,伴隨著更多的存儲(chǔ)空間碎浇,能導(dǎo)致OopMap內(nèi)容變化的指令很多,如果每一條指令都對(duì)應(yīng)一個(gè)OopMap璃俗,那么不僅存儲(chǔ)空間加劇奴璃,垃圾回收的成本也會(huì)提高。

? ? ? ? 針對(duì)上述問(wèn)題城豁,HotSpot認(rèn)為沒(méi)有必要為每條指令生成個(gè)一個(gè)OopMap苟穆,只用在特定的位置記錄,這些特定的位置被稱為安全點(diǎn),安全點(diǎn)決定程序執(zhí)行并非在任何指令的任何位置都能停頓下來(lái)開(kāi)始垃圾收集雳旅,而是必須到達(dá)安全點(diǎn)后才能夠暫停腺晾。對(duì)于安全點(diǎn)而言膨处,如何在垃圾收集發(fā)生時(shí),讓所有線程到達(dá)最近的安全點(diǎn)是不得不考慮的問(wèn)題。對(duì)此蔼紧,有兩種方案:搶先式中斷(Preemptive Suspension)?和主動(dòng)式中斷(Voluntary Suspension)

? ? ? ? (1)搶先式中斷:不需要線程執(zhí)行代碼去主動(dòng)配合,在垃圾收集時(shí)境蜕,系統(tǒng)會(huì)把所有用戶線程全部中斷撑教,如果發(fā)現(xiàn)有不在安全點(diǎn)上的用戶線程,就允許該線程繼續(xù)執(zhí)行偷遗,直到跑到安全點(diǎn)上再進(jìn)行中斷墩瞳。

? ? ? ? (2)主動(dòng)式中斷:設(shè)置一個(gè)標(biāo)志位,各線程執(zhí)行過(guò)程中不停的輪詢?cè)摌?biāo)志氏豌,一旦發(fā)現(xiàn)中斷標(biāo)志位true時(shí)喉酌,就自己在最近的安全點(diǎn)上主動(dòng)掛起,輪詢標(biāo)志的地方和安全點(diǎn)是重合的泵喘。

三泪电、安全區(qū)

? ? ? ? 針對(duì)于安全點(diǎn)的設(shè)計(jì),可能會(huì)引發(fā)線程無(wú)法響應(yīng)虛擬機(jī)中斷請(qǐng)求的場(chǎng)景(比如Sleep或者Blocked)纪铺,這時(shí)的線程無(wú)法走到安全點(diǎn)去掛起自己相速。因此,引入了另一概念鲜锚,安全區(qū)(Safe Region)突诬。

? ? ? ? 安全區(qū)是指能夠保證某一段代碼片段中,引用關(guān)系不會(huì)發(fā)生變化芜繁,該區(qū)域中任意地方開(kāi)始垃圾收集都是安全的旺隙。因此,安全區(qū)即視為是安全點(diǎn)的拉伸骏令。

? ? ? ? 用戶線程執(zhí)行到安全區(qū)的代碼時(shí)蔬捷,首先會(huì)標(biāo)識(shí)自己已經(jīng)進(jìn)入了安全區(qū),因此這段時(shí)間虛擬機(jī)發(fā)起垃圾回收時(shí)就不會(huì)去管這些處在安全區(qū)的線程榔袋。當(dāng)線程離開(kāi)安全區(qū)時(shí)周拐,它會(huì)檢查虛擬機(jī)是否已經(jīng)完成了根節(jié)點(diǎn)枚舉,如果完成了凰兑,則繼續(xù)執(zhí)行速妖;否則,該線程會(huì)一直等待聪黎,直到收到離開(kāi)安全區(qū)的信號(hào)罕容。

四备恤、記憶集

? ? ? ? 在分代收集理論中,為了區(qū)分跨代對(duì)象锦秒,垃圾收集器在新生代建立了記憶集(Remebered Set)這種數(shù)據(jù)結(jié)構(gòu)露泊,避免把老年代也加入根節(jié)點(diǎn)枚舉的掃描范圍。記憶集是一種用于記錄從非收集區(qū)域指向收集區(qū)域的指針集合的抽象數(shù)據(jù)結(jié)構(gòu)旅择。

? ? ? ? HotSpot采用一種被稱為“卡表”(Card Table)的方式去實(shí)現(xiàn)記憶集惭笑,卡表當(dāng)中存放了字節(jié)數(shù)組CARD_TABLE,數(shù)組的每一個(gè)元素對(duì)應(yīng)一塊特定大小的內(nèi)存區(qū)域生真,這個(gè)內(nèi)存區(qū)域被稱為“卡頁(yè)”沉噩。

圖 4-1 卡表與卡頁(yè)

? ? ? ? 一個(gè)卡頁(yè)的內(nèi)存中通常包含不止一個(gè)對(duì)象,只要卡頁(yè)內(nèi)存放的對(duì)象字段存在跨代指針柱蟀,就將該卡表的數(shù)組元素標(biāo)識(shí)為1川蒙,稱該元素?cái)?shù)據(jù)變臟(Dirty),反之长已,則標(biāo)識(shí)為0畜眨。在垃圾收集時(shí),只要篩選出卡表里變臟的元素术瓮,就能篩除存在跨代指針的元素康聂,把它們加入GC ROOTS一并掃描。

? ? ? ? 理論上講胞四,對(duì)象變臟的時(shí)間點(diǎn)是發(fā)生在引用類型字段賦值的那一刻恬汁,即其他分代區(qū)域中對(duì)象引用了本區(qū)域的對(duì)象。HotSpot虛擬機(jī)引入寫屏障(Write Barrier)技術(shù)來(lái)維護(hù)卡表狀態(tài)辜伟,類似于AOP切面的操作氓侧,在引用類型字段賦值時(shí)會(huì)產(chǎn)生一個(gè)環(huán)繞通知,供程序執(zhí)行額外的動(dòng)作游昼,在賦值前的寫屏障被稱為寫前屏障(Pre-Write Barrier),同理尝蠕,在賦值后的則稱為寫后屏障(Post-Write Barrier)烘豌。虛擬機(jī)會(huì)為所有的賦值操作生成相應(yīng)的指令。

? ? ? ? 為避免高并發(fā)場(chǎng)景下“偽共享”問(wèn)題看彼,即重復(fù)更新相同區(qū)域卡表的狀態(tài)而造成資源浪費(fèi)與性能損耗廊佩,JDK7之后,引入了參數(shù) -XX: +UseCondCardMark 來(lái)決定是否開(kāi)啟卡表更新的條件判斷靖榕,開(kāi)啟狀態(tài)下标锄,會(huì)先檢查卡表狀態(tài),如果卡表元素未被標(biāo)記過(guò)時(shí)茁计,才會(huì)將其標(biāo)記為變臟料皇。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子践剂,更是在濱河造成了極大的恐慌鬼譬,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逊脯,死亡現(xiàn)場(chǎng)離奇詭異优质,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)军洼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門巩螃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人匕争,你說(shuō)我怎么就攤上這事避乏。” “怎么了汗捡?”我有些...
    開(kāi)封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵淑际,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我扇住,道長(zhǎng)春缕,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任艘蹋,我火速辦了婚禮锄贼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘女阀。我一直安慰自己宅荤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布浸策。 她就那樣靜靜地躺著冯键,像睡著了一般。 火紅的嫁衣襯著肌膚如雪庸汗。 梳的紋絲不亂的頭發(fā)上惫确,一...
    開(kāi)封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音蚯舱,去河邊找鬼改化。 笑死,一個(gè)胖子當(dāng)著我的面吹牛枉昏,可吹牛的內(nèi)容都是我干的陈肛。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼兄裂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼句旱!你這毒婦竟也來(lái)了阳藻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤前翎,失蹤者是張志新(化名)和其女友劉穎稚配,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體港华,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡道川,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了立宜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冒萄。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖橙数,靈堂內(nèi)的尸體忽然破棺而出尊流,到底是詐尸還是另有隱情,我是刑警寧澤灯帮,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布崖技,位于F島的核電站,受9級(jí)特大地震影響钟哥,放射性物質(zhì)發(fā)生泄漏迎献。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一腻贰、第九天 我趴在偏房一處隱蔽的房頂上張望吁恍。 院中可真熱鬧,春花似錦播演、人聲如沸冀瓦。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)翼闽。三九已至,卻和暖如春洲炊,著一層夾襖步出監(jiān)牢的瞬間感局,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工选浑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蓝厌,地道東北人玄叠。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓古徒,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親读恃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子隧膘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

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