JVM回收跨代垃圾的方式詳解
1. 跨代引用概述
在Java堆內(nèi)存中,年輕代和老年代之間存在的對(duì)象相互引用,假設(shè)現(xiàn)在要進(jìn)行一次新生代的YGC,但新生代中的對(duì)象可能被老年代所引用的,為了找到新生代中的存活對(duì)象,不得不遍歷整個(gè)老年代。這樣明顯效率很低下,那么如何快速識(shí)別并回收這種引用對(duì)象呢?
這就不得不提到Card Table(卡表)
和 Remember Set(記憶集,簡稱RSet)
了。
2. 跨代引用的處理方式
2.1 卡表(Card Table)
卡表是一種用于跟蹤年輕代對(duì)象被老年代對(duì)象引用的數(shù)據(jù)結(jié)構(gòu)。它將堆內(nèi)存劃分為一系列固定大小的區(qū)域(卡片),每個(gè)卡片記錄了年輕代對(duì)象被老年代對(duì)象引用的情況。在老年代垃圾回收時(shí),垃圾收集器會(huì)掃描卡表,以確定哪些年輕代對(duì)象是存活的,即被老年代對(duì)象引用。
在 JVM 中,一個(gè) card 的大?。ㄍǔJ牵?12字節(jié)。在多線程并行收集時(shí),每個(gè)線程可以批量掃描多個(gè) card,一批 card 被稱為一個(gè) stride。默認(rèn)一個(gè) stride 含有 256個(gè) card,即每個(gè)線程要每次掃描 512 * 256 = 128 K 的內(nèi)存區(qū)域。stride數(shù)量太多就會(huì)導(dǎo)致線程在stride之間切換的開銷增加,進(jìn)而導(dǎo)致 GC Pause 增長, strides 太少恐怕也會(huì)導(dǎo)致單次掃描的時(shí)間增長,進(jìn)而影響整個(gè) GC Pause 。
2.2 記憶集(Remembered Sets)
伴隨 G1
垃圾收集器的誕生,傳統(tǒng)的老年代和新生代都從物理上的連續(xù)空間,變成了一個(gè)個(gè)物理上不連續(xù)的空間 region
。
JVM 針對(duì)這些Region 提供了一個(gè)數(shù)據(jù)結(jié)構(gòu),也就是 CSet(Collection Set)
,存儲(chǔ)任意年代的region
。
物理上不連續(xù)的 region
造成了新生代和老年的引用破碎化,新生代引用老年代,所以產(chǎn)生了 old->young
和young->old
的跨代對(duì)象引用,這時(shí)候 JVM 只要掃描 CSet
中的 R Set
即可。
邏輯上說每個(gè)Region都有一個(gè)RSet,RSet記錄了其他Region中的對(duì)象引用本Region中對(duì)象的關(guān)系。
每個(gè)Region會(huì)在自身的Remembered Set中紀(jì)錄下來自其他Region的指向自身的Card位置。這個(gè)Remembered Set
是一個(gè)Hash Table
,Key是別的Region的起始地址,Value是一個(gè)集合,里面的元素是Card Table
的Index。
RSet、Card和Region的關(guān)系
下圖表示了RSet、Card和Region的關(guān)系:
圖中是相互引用的三個(gè)region。R1 和 R3 的被細(xì)分到了card table 級(jí)別。R2 被 R1 和 R3的某些區(qū)域引用,所以 R2 的 RSet 會(huì)記錄到 R1 和 R2 的區(qū)域索引,即產(chǎn)生某些循環(huán)引用的作用。
一個(gè) Region 的 RSet 如果有值,至少可以證明這個(gè)區(qū)域是有引用的;一個(gè)區(qū)域如果無值,則可以認(rèn)為這個(gè)區(qū)域不可達(dá),可以不掃描這個(gè)區(qū)域(Card Table 可以減少 Minor GC 掃描 old 區(qū)來理解 young 區(qū)的時(shí)間,RSet 則可以減少掃描生成 CSet 選取候選 region 的時(shí)間)。
在做YGC的時(shí)候,只需要選定young generation region的RSet作為根集,這些RSet記錄了old->young的跨代引用,避免了掃描整個(gè)old generation。而mixed gc的時(shí)候,old generation中記錄了old->old的 RSet,young->old的引用由掃描全部young generation region(的 card table)得到,這樣也不用掃描全部old generation region。所以RSet的引入大大減少了GC的工作量。
2.3 處理器屏障(Processor Barriers)
處理器屏障是一種硬件支持的機(jī)制,用于跟蹤對(duì)象之間的引用關(guān)系。當(dāng)發(fā)生引用修改時(shí),處理器屏障可以監(jiān)測(cè)到對(duì)內(nèi)存的訪問,并通知垃圾收集器。垃圾收集器可以根據(jù)這些信息來更新引用關(guān)系,確??绱帽徽_處理。
3. 總結(jié)
卡表只解決 youngGC 掃老年代的問題,而 RSet 則解決了(G1 對(duì))所有 Region 的掃描問題。卡表通過對(duì)外引用提示我們應(yīng)該掃描什么區(qū)域,這樣我們可以避開不用掃描的區(qū)域;RSet通過對(duì)內(nèi)引用提示我們應(yīng)該掃描什么區(qū)域,這樣我們可以避開不用掃描的區(qū)域。
跨代引用的垃圾回收是Java虛擬機(jī)中一個(gè)復(fù)雜而重要的問題。通過合理設(shè)計(jì)和優(yōu)化記憶集、卡表等數(shù)據(jù)結(jié)構(gòu),并結(jié)合并發(fā)標(biāo)記-清除算法、處理器屏障等技術(shù),可以有效地處理跨代引用,保證垃圾回收的效率和穩(wěn)定性,從而提高Java應(yīng)用程序的性能和可靠性。
以上就是JVM回收跨代垃圾的方式詳解的詳細(xì)內(nèi)容,更多關(guān)于JVM回收跨代垃圾的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringMVC請(qǐng)求、響應(yīng)和攔截器的使用實(shí)例詳解
攔截器(Interceptor) 它是一個(gè)Spring組件,并由Spring容器管理,并不依賴Tomcat等容器,是可以單獨(dú)使用的,這篇文章給大家介紹SpringMVC請(qǐng)求、響應(yīng)和攔截器的使用,感興趣的朋友一起看看吧2024-03-03IntelliJ?IDEA社區(qū)版2021.3配置SpringBoot項(xiàng)目詳細(xì)教程及失敗案例
IntelliJ?IDEA?2021.3.3是一款集成開發(fā)環(huán)境,用于Java和其他編程語言的開發(fā),下面這篇文章主要給大家介紹了關(guān)于IntelliJ?IDEA社區(qū)版2021.3配置SpringBoot項(xiàng)目詳細(xì)教程及失敗案例的相關(guān)資料,需要的朋友可以參考下2024-03-03Java編程之多線程死鎖與線程間通信簡單實(shí)現(xiàn)代碼
這篇文章主要介紹了Java編程之多線程死鎖與線程間通信簡單實(shí)現(xiàn)代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10Java批量從svn導(dǎo)出多個(gè)項(xiàng)目代碼實(shí)例
這篇文章主要介紹了java批量從svn導(dǎo)出多個(gè)項(xiàng)目代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03RabbitMQ消費(fèi)者限流實(shí)現(xiàn)消息處理優(yōu)化
這篇文章主要介紹了RabbitMQ消費(fèi)者限流實(shí)現(xiàn)消息處理優(yōu)化,消費(fèi)者限流是用于消費(fèi)者每次獲取消息時(shí)限制條數(shù),注意前提是手動(dòng)確認(rèn)模式,并且在手動(dòng)確認(rèn)后才能獲取到消息,感興趣想要詳細(xì)了解可以參考下文2023-05-05Java CountDownLatch計(jì)數(shù)器與CyclicBarrier循環(huán)屏障
CountDownLatch是一種同步輔助,允許一個(gè)或多個(gè)線程等待其他線程中正在執(zhí)行的操作的ASET完成。它允許一組線程同時(shí)等待到達(dá)一個(gè)共同的障礙點(diǎn)2023-04-04配置JAVA環(huán)境變量中CLASSPATH變量的作用
這篇文章主要介紹了配置JAVA環(huán)境變量中CLASSPATH變量的作用,需要的朋友可以參考下2023-06-06SpringBoot整合Canal+RabbitMQ監(jiān)聽數(shù)據(jù)變更詳解
在現(xiàn)代分布式系統(tǒng)中,實(shí)時(shí)獲取數(shù)據(jù)庫的變更信息是一個(gè)常見的需求,本文將介紹SpringBoot如何通過整合Canal和RabbitMQ監(jiān)聽數(shù)據(jù)變更,需要的可以參考下2024-12-12一篇文章帶你理解Java Spring三級(jí)緩存和循環(huán)依賴
這篇文章主要介紹了淺談Spring 解決循環(huán)依賴必須要三級(jí)緩存嗎,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-09-09