jvm- 垃圾回收-01檢測(cè)對(duì)象是否可用

hotspot中 決定一個(gè)對(duì)象是否可用的 是根搜索算法。

根搜索算法

基本思路:通過(guò)一系列GCROOT作為起始點(diǎn),這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索過(guò)的路徑 稱(chēng)為引用鏈,當(dāng)一個(gè)對(duì)象和GCROOT之間沒(méi)有任何引用鏈時(shí),則證明對(duì)象是不可用的。

如下圖所示 ,ObjectA,ObjectB,ObjectC為可用,ObjectD與ObjectE不可用


根搜索算法

GC ROOT對(duì)象

  • 虛擬機(jī)棧(棧幀的本地變量表)中的引用的對(duì)象。
  • 方法區(qū)中的類(lèi)靜態(tài)屬性引用的對(duì)象。
  • 方法區(qū)中的常量引用的對(duì)象。
  • 本地方法棧中JNI(Native方法)的引用的對(duì)象。

如何獲得GCROOT對(duì)象

如果每次都完全遍歷方法區(qū)和棧,逐個(gè)檢查其引用關(guān)系,那么 每次都會(huì)消耗很多時(shí)間。
另外 可達(dá)性分析對(duì)執(zhí)行時(shí)間的敏感還體現(xiàn)在gc停頓上,因?yàn)檫@項(xiàng)工作必須在保持同一個(gè)版本號(hào)(引用關(guān)系不變)的快照中進(jìn)行。
由于目前主流的java虛擬機(jī)都是精準(zhǔn)式gc(知道一塊內(nèi)存是對(duì)象還是引用),所以當(dāng)執(zhí)行系統(tǒng)停頓,并不需要一個(gè)不漏地檢查完所有上下文和全局的引用位置。

hotsot是通過(guò)一組oopmap的數(shù)據(jù)結(jié)構(gòu)來(lái)達(dá)到這個(gè)目的的,在類(lèi)加載完成的時(shí)候,hotspot就把對(duì)象內(nèi)什么偏移量上是什么類(lèi)型的數(shù)據(jù)計(jì)算出來(lái),在jit編譯中,也會(huì)在特定的位置記錄下棧和寄存器中哪些位置是引用。這樣,jvm在掃描時(shí)可以直接得知這些信息。

這一部分參考文章:找出棧上的指針/引用

如何加速維護(hù)oopmap

在oopmap的協(xié)助下,hotspot可以較快的完成gc root枚舉,但是一個(gè)很現(xiàn)實(shí)的問(wèn)題隨之而來(lái):可能導(dǎo)致引用關(guān)系變化,或者說(shuō)oopmap內(nèi)部?jī)?nèi)容變化的指令非常多,我不可能每次都生成對(duì)應(yīng)的oopmap,那會(huì)需要大量空間,同時(shí)gc耗時(shí)也會(huì)增加。

為了解決這一問(wèn)題。 hotspot做了如下措施:
沒(méi)有為每條指令生成oopmap,只有在特定的地方記錄這些信息,這些信息就是安全點(diǎn)(safepoint),即程序運(yùn)行時(shí)并非所有地方都能停下,必須到safepoint才可以進(jìn)行枚舉根節(jié)點(diǎn)。
但是 做了這一措施后又會(huì)面臨如下問(wèn)題

  1. 如果safepoint的間隔過(guò)長(zhǎng),那么 每次維護(hù)oopmap的時(shí)間就會(huì)很長(zhǎng);
  2. 如果safepoint的間隔過(guò)短,吞吐量可能會(huì)比較低。

如何到達(dá)safepoint

這里還有另外一個(gè)問(wèn)題,我們?cè)摬捎?strong>主動(dòng)式中斷還是搶先式中斷:

  1. 搶占式中斷:不需要線程的執(zhí)行代碼配合,在維護(hù)oopmap發(fā)生時(shí),直接把所有線程中斷,如果發(fā)現(xiàn)有線程中斷的地方不在安全點(diǎn),就恢復(fù)線程,讓他"跑"到安全點(diǎn)。
  2. 主動(dòng)式中斷:主動(dòng)式中斷是通過(guò)維護(hù)oopmap需要實(shí)現(xiàn)中斷線程的時(shí)候,不直接操作線程操作,僅僅是設(shè)置一個(gè)標(biāo)志,各個(gè)線程執(zhí)行主動(dòng)輪詢(xún)這個(gè)標(biāo)志,發(fā)現(xiàn)中斷標(biāo)志為真時(shí)自己中斷掛機(jī)。輪詢(xún)標(biāo)志的地方和安全點(diǎn)是重合的,另外加上創(chuàng)建對(duì)象需要分配內(nèi)存的地方。

并不是所有線程都可以到達(dá)safepoint

并不是所有線程都可以到達(dá)safepoint,比如有線程沒(méi)有執(zhí)行,如何解決這一問(wèn)題?

安全區(qū)域(safe region)

安全區(qū)域是指一段代碼片段中,引用關(guān)系不會(huì)發(fā)生變化。在這個(gè)區(qū)域的任何地方都可以維護(hù)oopmap。
在線程執(zhí)行到safe region的代碼時(shí),首先標(biāo)識(shí)自己進(jìn)入了safe region。這樣維護(hù)oopmap的時(shí)候就不會(huì)管這些已經(jīng)在safe region的線程。
通過(guò)這一方法解決了部分線程無(wú)法到達(dá)safepint 的問(wèn)題。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容