最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JVM GC垃圾回收算法使用及說(shuō)明

 更新時(shí)間:2025年10月15日 09:28:31   作者:backRoads  
文章詳細(xì)討論了JVM的垃圾回收算法,包括標(biāo)記-清除、復(fù)制算法、標(biāo)記-整理以及分代收集,每種方法的執(zhí)行流程、優(yōu)缺點(diǎn)以及適用場(chǎng)景都有詳盡說(shuō)明,此外,還介紹了可達(dá)性算法作為JVM垃圾回收的核心機(jī)制,解釋了如何確定對(duì)象是否存活

垃圾回收算法(GC Algorithms)

JVM 根據(jù)對(duì)象生命周期特性(分代假設(shè))采用不同的回收算法,核心算法包括:

標(biāo)記-清除(Mark-Sweep)

此算法執(zhí)行分兩階段。第一階段從引用根節(jié)點(diǎn)開(kāi)始標(biāo)記所有被引用的對(duì)象,第二階段遍歷整個(gè)堆,把未標(biāo)記的對(duì)象清除。

  • 流程??:標(biāo)記所有存活對(duì)象 → 清除未標(biāo)記對(duì)象。
  • ??優(yōu)點(diǎn)??:簡(jiǎn)單、無(wú)對(duì)象移動(dòng)開(kāi)銷。
  • ??缺點(diǎn)??:內(nèi)存碎片化、效率較低(需遍歷兩次堆)。

復(fù)制算法(Copying)

此算法把內(nèi)存空間劃為兩個(gè)相等的區(qū)域,每次只使用其中一個(gè)區(qū)域。垃圾回收時(shí),遍歷當(dāng)前使用區(qū)域,把正在使用中的對(duì)象復(fù)制到另外一個(gè)區(qū)域中。此算法每次只處理正在使用中的對(duì)象,因此復(fù)制成本比較小, 同時(shí)復(fù)制過(guò)去以后還能進(jìn)行相應(yīng)的內(nèi)存整理,不會(huì)出現(xiàn)“碎片”問(wèn)題。當(dāng)然,此算法的缺點(diǎn)也是很明顯的,就是需要兩倍內(nèi)存空間。

  • ?流程??:將存活對(duì)象復(fù)制到另一塊內(nèi)存區(qū)域 → 清空原區(qū)域。
  • ??優(yōu)點(diǎn)??:無(wú)碎片、效率高(適用于存活率低的對(duì)象,如新生代)。
  • ??缺點(diǎn)??:內(nèi)存利用率低(需預(yù)留一半空間)。

??標(biāo)記-整理(Mark-Compact)

此算法結(jié)合了“標(biāo)記-清除”和“復(fù)制”兩個(gè)算法的優(yōu)點(diǎn)。也是分兩階段,第一階段從根節(jié)點(diǎn)開(kāi)始標(biāo)記所有被引用對(duì)象,第二階段遍歷整個(gè)堆,把清除未標(biāo)記對(duì)象并且把存活對(duì)象“壓縮”到堆的其中一塊,按順序排放。此算法避免了“標(biāo)記-清除”的碎片問(wèn)題,同時(shí)也避免了“復(fù)制”算法的空間問(wèn)題。

  • 流程??:標(biāo)記存活對(duì)象 → 移動(dòng)對(duì)象到內(nèi)存一端 → 清理邊界外內(nèi)存。
  • ??優(yōu)點(diǎn)??:無(wú)碎片、內(nèi)存利用率高。
  • ??缺點(diǎn)??:對(duì)象移動(dòng)開(kāi)銷大(適用于老年代)。

分代收集(Generational Collection)

  • 核心思想??:根據(jù)對(duì)象存活時(shí)間劃分內(nèi)存區(qū)域(新生代、老年代)。
  • ??新生代??:存活率低 → 使用復(fù)制算法(如 Serial、ParNew)。
  • 老年代??:存活率高 → 使用標(biāo)記-清除或標(biāo)記-整理算法(如 CMS、G1)。

可達(dá)性算法(Reachability Analysis)

可達(dá)性算法(??Reachability Analysis??)是 JVM 垃圾回收的核心機(jī)制,用于判斷對(duì)象是否存活。

其核心思想是:??從一組根對(duì)象(GC Roots)出發(fā),遍歷所有引用鏈,未被引用的對(duì)象視為可回收垃圾??。以下是其詳細(xì)原理、流程和應(yīng)用場(chǎng)景:

可達(dá)性算法的基本流程?

1.??確定 GC Roots??

JVM 枚舉所有根對(duì)象(如棧幀中的局部變量、靜態(tài)變量等),作為遍歷起點(diǎn)。

2.遍歷引用鏈??

從 GC Roots 出發(fā),遞歸遍歷所有直接或間接引用的對(duì)象,形成??對(duì)象圖(Object Graph)??。

3.??標(biāo)記存活對(duì)象??

所有被遍歷到的對(duì)象標(biāo)記為存活(如使用三色標(biāo)記法中的黑色或灰色狀態(tài))。

4.??回收不可達(dá)對(duì)象??

未被遍歷到的對(duì)象(白色對(duì)象)視為垃圾,由具體 GC 算法回收(如標(biāo)記-清除、復(fù)制等)。

GC Roots 的具體類型?

以下對(duì)象被定義為 GC Roots,不會(huì)被回收:

虛擬機(jī)棧中的引用??

當(dāng)前執(zhí)行方法的局部變量、方法參數(shù)(如 public void foo(Object param))。

當(dāng)前線程的調(diào)用棧中所有方法的局部變量。

本地方法棧中的引用??

JNI(Java Native Interface)方法中的對(duì)象引用(如通過(guò) JNIEnv 調(diào)用的對(duì)象)。

方法區(qū)的靜態(tài)變量和常量??

類的靜態(tài)變量(static 修飾)。

字符串常量池中的引用(如 String s = “abc”)。

同步鎖持有的對(duì)象??

通過(guò) synchronized 關(guān)鍵字鎖定的對(duì)象(如 synchronized(obj) 中的 obj)。

JVM 內(nèi)部對(duì)象??

系統(tǒng)類加載器(ClassLoader)加載的類。

異常對(duì)象(如 OutOfMemoryError)、線程對(duì)象等。

跨代引用記錄對(duì)象??

卡表(Card Table)中記錄的老年代對(duì)新生代的引用(需特殊處理)。

引用類型對(duì)可達(dá)性的影響?

引用類型強(qiáng)引用(Strong)軟引用(Soft)弱引用(Weak)虛引用(Phantom)
定義?默認(rèn)引用(Object obj = new Object())內(nèi)存不足時(shí)回收(SoftReference)下次 GC 必回收(WeakReference)僅用于跟蹤對(duì)象回收(PhantomReference)
??可達(dá)性影響?強(qiáng)可達(dá)軟可達(dá)弱可達(dá)不可達(dá)
??回收條件?不可達(dá)時(shí)回收內(nèi)存不足時(shí)回收無(wú)論內(nèi)存是否充足均回收對(duì)象回收后入隊(duì)通知

示例:

Object strongRef = new Object();          // 強(qiáng)引用
SoftReference<Object> softRef = new SoftReference<>(new Object());
WeakReference<Object> weakRef = new WeakReference<>(new Object());
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), new ReferenceQueue<>());

三色標(biāo)記(Tri-color Marking)

定義

用三種顏色抽象對(duì)象的狀態(tài):

??白色(White)??

  • ??初始狀態(tài)??:對(duì)象未被訪問(wèn)(未標(biāo)記)。
  • ??最終回收??:標(biāo)記完成后仍為白色的對(duì)象視為可回收垃圾。

??灰色(Gray)??

  • ??中間狀態(tài)??:對(duì)象被標(biāo)記為存活,但其子引用(成員變量、數(shù)組元素等)尚未被遍歷。

??黑色(Black)??

  • ??最終存活狀態(tài)??:對(duì)象被標(biāo)記為存活,且所有子引用已被遍歷完成。

標(biāo)記流程(基本步驟)?

??初始階段

  • 所有對(duì)象設(shè)為白色。
  • 將 GC Roots 直接引用的對(duì)象標(biāo)記為灰色(放入灰色隊(duì)列)。

標(biāo)記階段(并發(fā))

從灰色隊(duì)列中取出對(duì)象:

  • —遍歷該對(duì)象的所有子引用,將子引用指向的白色對(duì)象標(biāo)記為灰色。
  • —將當(dāng)前對(duì)象標(biāo)記為黑色。
  • 重復(fù)上述過(guò)程,直到灰色隊(duì)列為空。

??最終階段

所有存活對(duì)象應(yīng)為黑色,白色對(duì)象視為垃圾。

并發(fā)標(biāo)記的兩種問(wèn)題?

因用戶線程與 GC 線程并發(fā)運(yùn)行,對(duì)象引用可能發(fā)生變化,導(dǎo)致兩種風(fēng)險(xiǎn):

漏標(biāo)(對(duì)象丟失)

場(chǎng)景??:

黑色對(duì)象(已標(biāo)記完成)被用戶線程寫(xiě)入了一個(gè)新的白色對(duì)象引用。

用戶線程刪除了灰色對(duì)象到某個(gè)白色對(duì)象的引用。

結(jié)果??:

白色對(duì)象未被標(biāo)記為存活,導(dǎo)致被錯(cuò)誤回收。

例??:

初始:黑(A) → 灰(B) → 白(C) → 白(D)
B 即將處理,但此時(shí)用戶線程執(zhí)行:
1. A.field = D   // 黑對(duì)象引用了白對(duì)象
2. B.field = null // 斷開(kāi)灰對(duì)象到C的引用
最終:C未標(biāo)記(白色),D未標(biāo)記(白色),會(huì)被誤回收。

解決

1. 增量更新(Incremental Update)??

  • ??原理??:記錄新插入的引用,重新標(biāo)記。
  • ??實(shí)現(xiàn)??:當(dāng)用戶線程將黑色對(duì)象插入對(duì)白色對(duì)象的引用時(shí),通過(guò)??寫(xiě)屏障(Write Barrier)?? 將黑色對(duì)象重新標(biāo)記為灰色。
  • ??示例 GC??:CMS(Concurrent Mark-Sweep)。

??2. 原始快照(SATB, Snapshot At The Beginning)??

  • ??原理??:基于標(biāo)記開(kāi)始時(shí)存在的對(duì)象引用關(guān)系快照(即假設(shè)這些對(duì)象是存活的)。
  • ??實(shí)現(xiàn)??:當(dāng)用戶線程修改引用關(guān)系(如刪除一個(gè)引用),通過(guò)寫(xiě)屏障將舊引用的目標(biāo)對(duì)象標(biāo)記為灰色。
  • ??示例 GC??:G1、ZGC、Shenandoah。

錯(cuò)標(biāo)(浮動(dòng)垃圾)

場(chǎng)景??:

對(duì)象實(shí)際已死亡,但在標(biāo)記階段被標(biāo)記為存活。

解決:

??可容忍??:僅導(dǎo)致少量?jī)?nèi)存未及時(shí)釋放,下次 GC 可清理。

OopMap(Ordinary Object Pointer Map)

OopMap 記錄了棧上本地變量到堆上對(duì)象的引用關(guān)系。其作用是:垃圾收集時(shí),收集線程會(huì)對(duì)棧上的內(nèi)存進(jìn)行掃描,看看哪些位置存儲(chǔ)了 Reference 類型。如果發(fā)現(xiàn)某個(gè)位置確實(shí)存的是 Reference 類型,就意味著它所引用的對(duì)象這一次不能被回收。但問(wèn)題是,棧上的本地變量表里面只有一部分?jǐn)?shù)據(jù)是 Reference 類型的(它們是我們所需要的),那些非 Reference 類型的數(shù)據(jù)對(duì)我們而言毫無(wú)用處,但我們還是不得不對(duì)整個(gè)棧全部掃描一遍,這是對(duì)時(shí)間和資源的一種浪費(fèi)。

一個(gè)很自然的想法是,能不能用空間換時(shí)間,在某個(gè)時(shí)候把棧上代表引用的位置全部記錄下來(lái),這樣到真正 gc 的時(shí)候就可以直接讀取,而不用再一點(diǎn)一點(diǎn)的掃描了。事實(shí)上,大部分主流的虛擬機(jī)也正是這么做的,比如 HotSpot ,它使用一種叫做 OopMap 的數(shù)據(jù)結(jié)構(gòu)來(lái)記錄這類信息。

我們知道,一個(gè)線程意味著一個(gè)棧,一個(gè)棧由多個(gè)棧幀組成,一個(gè)棧幀對(duì)應(yīng)著一個(gè)方法,一個(gè)方法里面可能有多個(gè)安全點(diǎn)。 gc 發(fā)生時(shí),程序首先運(yùn)行到最近的一個(gè)安全點(diǎn)停下來(lái),然后更新自己的 OopMap ,記下棧上哪些位置代表著引用。枚舉根節(jié)點(diǎn)時(shí),遞歸遍歷每個(gè)棧幀的 OopMap ,通過(guò)棧中記錄的被引用對(duì)象的內(nèi)存地址,即可找到這些對(duì)象( GC Roots )。

OopMap(Ordinary Object Pointer Map)是 JVM 用于??快速定位 GC Roots?? 的關(guān)鍵數(shù)據(jù)結(jié)構(gòu),通過(guò)記錄棧幀和寄存器中的對(duì)象引用位置,顯著減少垃圾回收時(shí)的停頓時(shí)間(Stop-The-World, STW)。以下是其生成時(shí)機(jī)及作用機(jī)制的詳細(xì)解析:

OopMap 的生成時(shí)機(jī)?

OopMap 的生成與 ??JIT 編譯器?? 和 ??安全點(diǎn)(Safe Point)?? 密切相關(guān),主要發(fā)生在以下場(chǎng)景:

方法編譯時(shí)(JIT 階段)?

??即時(shí)編譯(JIT)??:

當(dāng)方法被 JIT 編譯器編譯為本地機(jī)器碼時(shí),編譯器會(huì)分析方法的棧幀布局,并生成對(duì)應(yīng)的 OopMap。

??記錄內(nèi)容??:

棧幀中哪些位置(偏移量)存儲(chǔ)了對(duì)象引用(Oop,Ordinary Object Pointer)。如:局部變量表、方法參數(shù)、this 指針等。

??示例??:

若方法的局部變量表第 3 個(gè)槽位是 Object obj,則 OopMap 會(huì)記錄該槽位的偏移量。

安全點(diǎn)(Safe Point)?

  • ??安全點(diǎn)觸發(fā)??:當(dāng) JVM 需要執(zhí)行 GC、代碼反優(yōu)化等操作時(shí),所有用戶線程必須暫停在安全點(diǎn)。
  • ??安全點(diǎn)位置??:通常插入在方法調(diào)用、循環(huán)回邊(如 for 循環(huán))、異常拋出等位置(避免長(zhǎng)時(shí)間不進(jìn)入安全點(diǎn))。
  • ??OopMap 更新??:在安全點(diǎn)處,JVM 會(huì)生成或更新當(dāng)前線程的 OopMap,確保準(zhǔn)確記錄此時(shí)棧幀和寄存器中的引用。

GC 僅是觸發(fā)安全點(diǎn)的一種場(chǎng)景,其他操作(如偏向鎖撤銷)也會(huì)觸發(fā)安全點(diǎn)。

??并非所有 OopMap 都在 GC 前生成??,但 GC 前必須依賴安全點(diǎn)更新 OopMap。

特定指令插入?

顯式生成指令??:JIT 編譯器會(huì)在生成的機(jī)器碼中插入特殊指令(如 test 指令),用于檢查是否需要進(jìn)入安全點(diǎn)并生成 OopMap。

OopMap 如何協(xié)助 JVM 獲取 GC Roots?

GC Roots 是垃圾回收的起點(diǎn),包括??棧幀中的局部變量、靜態(tài)變量、JNI 引用等??。

OopMap 的作用是快速枚舉這些根引用,避免全棧掃描。

快速定位引用位置?

  • 直接映射??:OopMap 明確記錄了棧幀中哪些位置存儲(chǔ)了對(duì)象引用(如局部變量、方法參數(shù))。
  • ??寄存器記錄??:部分引用可能存儲(chǔ)在寄存器中(如 this 指針),OopMap 也會(huì)記錄這些寄存器的名稱。

結(jié)合安全點(diǎn)減少 STW 時(shí)間?

  • ??暫停線程??:當(dāng) GC 觸發(fā)時(shí),所有線程需快速暫停在安全點(diǎn)。
  • ??遍歷 OopMap??:GC 線程直接讀取各線程的 OopMap,遍歷記錄的引用位置,收集所有 GC Roots。
  • ??無(wú)需全棧掃描??:避免逐字節(jié)檢查整個(gè)棧內(nèi)存,極大縮短暫停時(shí)間。

與卡表(Card Table)協(xié)作?

  • 維護(hù)跨代引用??:卡表用于記錄老年代到新生代的引用,OopMap 幫助快速定位這些引用所在的?;蚣拇嫫魑恢谩?/li>
  • ??寫(xiě)屏障支持??:當(dāng)用戶線程修改對(duì)象引用時(shí),寫(xiě)屏障會(huì)更新卡表,而 OopMap 確保這些修改在 GC 時(shí)被正確識(shí)別。

OopMap 與 GC 流程的協(xié)作?

以 ??Young GC?? 為例,流程如下:

1.??觸發(fā) GC??:新生代空間不足,需回收。

??2.進(jìn)入安全點(diǎn)??:所有用戶線程暫停,生成 OopMap。

3.??枚舉 GC Roots??:

  • —根據(jù) OopMap 遍歷所有線程的棧幀和寄存器,收集指向新生代的引用(如局部變量 obj)。
  • —結(jié)合卡表,找到老年代中指向新生代的對(duì)象。

4.??標(biāo)記存活對(duì)象??:從 GC Roots 出發(fā),標(biāo)記所有可達(dá)對(duì)象。

5.??恢復(fù)線程??:完成 GC 后,線程繼續(xù)執(zhí)行。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決SpringMvc后臺(tái)接收json數(shù)據(jù)中文亂碼問(wèn)題的幾種方法

    解決SpringMvc后臺(tái)接收json數(shù)據(jù)中文亂碼問(wèn)題的幾種方法

    本篇文章主要介紹了解決SpringMvc后臺(tái)接收json數(shù)據(jù)中文亂碼問(wèn)題的幾種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Java struts2 validate用戶登錄校驗(yàn)功能實(shí)現(xiàn)

    Java struts2 validate用戶登錄校驗(yàn)功能實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了Java struts2 validate用戶登錄校驗(yàn)功能實(shí)現(xiàn)的具體步驟,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • java解析XML詳解

    java解析XML詳解

    這篇文章主要介紹了XML解析四種方式代碼示例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-07-07
  • SpringBoot+Elasticsearch實(shí)現(xiàn)數(shù)據(jù)搜索的方法詳解

    SpringBoot+Elasticsearch實(shí)現(xiàn)數(shù)據(jù)搜索的方法詳解

    Elasticsearch是一個(gè)基于Lucene的搜索服務(wù)器。它提供了一個(gè)分布式多用戶能力的全文搜索引擎,基于RESTful?web接口。本文將利用SpringBoot整合Elasticsearch實(shí)現(xiàn)海量級(jí)數(shù)據(jù)搜索,需要的可以參考一下
    2022-05-05
  • Java通過(guò)socket客戶端保持連接服務(wù)端實(shí)現(xiàn)代碼

    Java通過(guò)socket客戶端保持連接服務(wù)端實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java通過(guò)socket客戶端保持連接服務(wù)端實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • MyBatis整合Redis實(shí)現(xiàn)二級(jí)緩存的示例代碼

    MyBatis整合Redis實(shí)現(xiàn)二級(jí)緩存的示例代碼

    這篇文章主要介紹了MyBatis整合Redis實(shí)現(xiàn)二級(jí)緩存的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 淺談MyBatis循環(huán)Map(高級(jí)用法)

    淺談MyBatis循環(huán)Map(高級(jí)用法)

    這篇文章主要介紹了淺談MyBatis循環(huán)Map(高級(jí)用法),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • 詳解如何使用maven生成可以執(zhí)行的jar

    詳解如何使用maven生成可以執(zhí)行的jar

    這篇文章主要介紹了詳解如何使用maven生成可以執(zhí)行的jar,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • spring5 SAXParseException:cvc-elt.1: 找不到元素“beans 的聲明詳解

    spring5 SAXParseException:cvc-elt.1: 找不到元素“beans 的聲明詳解

    這篇文章主要給大家介紹了關(guān)于spring5 SAXParseException:cvc-elt.1: 找不到元素“beans 聲明的相關(guān)資料,需要的朋友可以參考下
    2020-08-08
  • Springboot中LocalDateTime對(duì)象返回給前端格式化解決方案

    Springboot中LocalDateTime對(duì)象返回給前端格式化解決方案

    在項(xiàng)目開(kāi)發(fā)當(dāng)中前后端使用什么樣的時(shí)間格式,是一個(gè)值得關(guān)注的問(wèn)題,這篇文章主要給大家介紹了關(guān)于Springboot中LocalDateTime對(duì)象返回給前端格式化的解決方案,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-04-04

最新評(píng)論

彰武县| 临桂县| 新昌县| 吉安市| 筠连县| 天津市| 庐江县| 青岛市| 黄骅市| 突泉县| 平泉县| 巴彦淖尔市| 西昌市| 东台市| 甘德县| 青海省| 临邑县| 绥化市| 宁陕县| 三明市| 葫芦岛市| 手机| 文昌市| 兴化市| 唐海县| 靖安县| 永吉县| 安康市| 井陉县| 逊克县| 常山县| 铜梁县| 泸水县| 大名县| 新营市| 宁德市| 河源市| 渑池县| 聊城市| 修文县| 锦屏县|