JVM GC垃圾回收算法

垃圾回收算法(GC Algorithms)

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

標記-清除(Mark-Sweep)

此算法執行分兩階段。第一階段從引用根節點開始標記所有被引用的對象,第二階段遍歷整個堆,把未標記的對象清除。
流程??:標記所有存活對象 → 清除未標記對象。
??優點??:簡單、無對象移動開銷。
??缺點??:內存碎片化、效率較低(需遍歷兩次堆)。
在這里插入圖片描述

復制算法(Copying)

此算法把內存空間劃為兩個相等的區域,每次只使用其中一個區域。垃圾回收時,遍歷當前使用區域,把正在使用中的對象復制到另外一個區域中。此算法每次只處理正在使用中的對象,因此復制成本比較小, 同時復制過去以后還能進行相應的內存整理,不會出現“碎片”問題。當然,此算法的缺點也是很明顯的,就是需要兩倍內存空間。
?流程??:將存活對象復制到另一塊內存區域 → 清空原區域。
??優點??:無碎片、效率高(適用于存活率低的對象,如新生代)。
??缺點??:內存利用率低(需預留一半空間)。
在這里插入圖片描述

??標記-整理(Mark-Compact)

此算法結合了“標記-清除”和“復制”兩個算法的優點。也是分兩階段,第一階段從根節點開始標記所有被引用對象,第二階段遍歷整個堆,把清除未標記對象并且把存活對象“壓縮”到堆的其中一塊,按順序排放。此算法避免了“標記-清除”的碎片問題,同時也避免了“復制”算法的空間問題。
流程??:標記存活對象 → 移動對象到內存一端 → 清理邊界外內存。
??優點??:無碎片、內存利用率高。
??缺點??:對象移動開銷大(適用于老年代)。
在這里插入圖片描述

分代收集(Generational Collection)

核心思想??:根據對象存活時間劃分內存區域(新生代、老年代)。
??新生代??:存活率低 → 使用復制算法(如 Serial、ParNew)。
?? 老年代??:存活率高 → 使用標記-清除或標記-整理算法(如 CMS、G1)。

可達性算法(Reachability Analysis)

可達性算法(??Reachability Analysis??)是 JVM 垃圾回收的核心機制,用于判斷對象是否存活。其核心思想是:??從一組根對象(GC Roots)出發,遍歷所有引用鏈,未被引用的對象視為可回收垃圾??。以下是其詳細原理、流程和應用場景:
在這里插入圖片描述

可達性算法的基本流程?

1.??確定 GC Roots??
JVM 枚舉所有根對象(如棧幀中的局部變量、靜態變量等),作為遍歷起點。
2.遍歷引用鏈??
從 GC Roots 出發,遞歸遍歷所有直接或間接引用的對象,形成??對象圖(Object Graph)??。
3.??標記存活對象??
所有被遍歷到的對象標記為存活(如使用三色標記法中的黑色或灰色狀態)。
4.??回收不可達對象??
未被遍歷到的對象(白色對象)視為垃圾,由具體 GC 算法回收(如標記-清除、復制等)。

GC Roots 的具體類型?

以下對象被定義為 GC Roots,不會被回收:

虛擬機棧中的引用??

當前執行方法的局部變量、方法參數(如 public void foo(Object param))。
當前線程的調用棧中所有方法的局部變量。

本地方法棧中的引用??

JNI(Java Native Interface)方法中的對象引用(如通過 JNIEnv 調用的對象)。

方法區的靜態變量和常量??

類的靜態變量(static 修飾)。
字符串常量池中的引用(如 String s = “abc”)。

同步鎖持有的對象??

通過 synchronized 關鍵字鎖定的對象(如 synchronized(obj) 中的 obj)。

JVM 內部對象??

系統類加載器(ClassLoader)加載的類。
異常對象(如 OutOfMemoryError)、線程對象等。

跨代引用記錄對象??

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

引用類型對可達性的影響?

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

示例:

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

三色標記(Tri-color Marking)

定義

用三種顏色抽象對象的狀態:
??白色(White)??
??初始狀態??:對象未被訪問(未標記)。
??最終回收??:標記完成后仍為白色的對象視為可回收垃圾。
??灰色(Gray)??
??中間狀態??:對象被標記為存活,但其子引用(成員變量、數組元素等)尚未被遍歷。
??黑色(Black)??
??最終存活狀態??:對象被標記為存活,且所有子引用已被遍歷完成。

標記流程(基本步驟)?

??初始階段

所有對象設為白色。
將 GC Roots 直接引用的對象標記為灰色(放入灰色隊列)。

標記階段(并發)

從灰色隊列中取出對象:
—遍歷該對象的所有子引用,將子引用指向的白色對象標記為灰色。
—將當前對象標記為黑色。
重復上述過程,直到灰色隊列為空。

??最終階段

所有存活對象應為黑色,白色對象視為垃圾。

并發標記的兩種問題?

因用戶線程與 GC 線程并發運行,對象引用可能發生變化,導致兩種風險:

漏標(對象丟失)

場景??:

黑色對象(已標記完成)被用戶線程寫入了一個新的白色對象引用。
用戶線程刪除了灰色對象到某個白色對象的引用。

結果??:

白色對象未被標記為存活,導致被錯誤回收。
例??:

初始:黑(A) → 灰(B) → 白(C) → 白(D)
B 即將處理,但此時用戶線程執行:
1. A.field = D   // 黑對象引用了白對象
2. B.field = null // 斷開灰對象到C的引用
最終:C未標記(白色),D未標記(白色),會被誤回收。
解決
  1. 增量更新(Incremental Update)??
    ??原理??:記錄新插入的引用,重新標記。
    ??實現??:當用戶線程將黑色對象插入對白色對象的引用時,通過??寫屏障(Write Barrier)?? 將黑色對象重新標記為灰色。
    ??示例 GC??:CMS(Concurrent Mark-Sweep)。
    ??2. 原始快照(SATB, Snapshot At The Beginning)??
    ??原理??:基于標記開始時存在的對象引用關系快照(即假設這些對象是存活的)。
    ??實現??:當用戶線程修改引用關系(如刪除一個引用),通過寫屏障將舊引用的目標對象標記為灰色。
    ??示例 GC??:G1、ZGC、Shenandoah。

錯標(浮動垃圾)

場景??:

對象實際已死亡,但在標記階段被標記為存活。

解決:

??可容忍??:僅導致少量內存未及時釋放,下次 GC 可清理。

OopMap(Ordinary Object Pointer Map)

OopMap 記錄了棧上本地變量到堆上對象的引用關系。其作用是:垃圾收集時,收集線程會對棧上的內存進行掃描,看看哪些位置存儲了 Reference 類型。如果發現某個位置確實存的是 Reference 類型,就意味著它所引用的對象這一次不能被回收。但問題是,棧上的本地變量表里面只有一部分數據是 Reference 類型的(它們是我們所需要的),那些非 Reference 類型的數據對我們而言毫無用處,但我們還是不得不對整個棧全部掃描一遍,這是對時間和資源的一種浪費。
一個很自然的想法是,能不能用空間換時間,在某個時候把棧上代表引用的位置全部記錄下來,這樣到真正 gc 的時候就可以直接讀取,而不用再一點一點的掃描了。事實上,大部分主流的虛擬機也正是這么做的,比如 HotSpot ,它使用一種叫做 OopMap 的數據結構來記錄這類信息。
我們知道,一個線程意味著一個棧,一個棧由多個棧幀組成,一個棧幀對應著一個方法,一個方法里面可能有多個安全點。 gc 發生時,程序首先運行到最近的一個安全點停下來,然后更新自己的 OopMap ,記下棧上哪些位置代表著引用。枚舉根節點時,遞歸遍歷每個棧幀的 OopMap ,通過棧中記錄的被引用對象的內存地址,即可找到這些對象( GC Roots )。

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

OopMap 的生成時機?

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

方法編譯時(JIT 階段)?

??即時編譯(JIT)??:
當方法被 JIT 編譯器編譯為本地機器碼時,編譯器會分析方法的棧幀布局,并生成對應的 OopMap。
??記錄內容??:
棧幀中哪些位置(偏移量)存儲了對象引用(Oop,Ordinary Object Pointer)。如:局部變量表、方法參數、this 指針等。
??示例??:
若方法的局部變量表第 3 個槽位是 Object obj,則 OopMap 會記錄該槽位的偏移量。

安全點(Safe Point)?

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

GC 僅是觸發安全點的一種場景,其他操作(如偏向鎖撤銷)也會觸發安全點。
??并非所有 OopMap 都在 GC 前生成??,但 GC 前必須依賴安全點更新 OopMap。

特定指令插入?

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

OopMap 如何協助 JVM 獲取 GC Roots?

GC Roots 是垃圾回收的起點,包括??棧幀中的局部變量、靜態變量、JNI 引用等??。OopMap 的作用是快速枚舉這些根引用,避免全棧掃描。

快速定位引用位置?

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

結合安全點減少 STW 時間?

??暫停線程??:當 GC 觸發時,所有線程需快速暫停在安全點。
??遍歷 OopMap??:GC 線程直接讀取各線程的 OopMap,遍歷記錄的引用位置,收集所有 GC Roots。
??無需全棧掃描??:避免逐字節檢查整個棧內存,極大縮短暫停時間。

與卡表(Card Table)協作?

維護跨代引用??:卡表用于記錄老年代到新生代的引用,OopMap 幫助快速定位這些引用所在的棧或寄存器位置。
??寫屏障支持??:當用戶線程修改對象引用時,寫屏障會更新卡表,而 OopMap 確保這些修改在 GC 時被正確識別。

OopMap 與 GC 流程的協作?

以 ??Young GC?? 為例,流程如下:
1.??觸發 GC??:新生代空間不足,需回收。
??2.進入安全點??:所有用戶線程暫停,生成 OopMap。
3.??枚舉 GC Roots??:
—根據 OopMap 遍歷所有線程的棧幀和寄存器,收集指向新生代的引用(如局部變量 obj)。
—結合卡表,找到老年代中指向新生代的對象。
4.??標記存活對象??:從 GC Roots 出發,標記所有可達對象。
5.??恢復線程??:完成 GC 后,線程繼續執行。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/79180.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/79180.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/79180.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數智化招標采購系統針對供應商管理解決方案(采購如何管控供應商)

隨著《優化營商環境條例》深化實施&#xff0c;采購領域正通過政策驅動和技術賦能&#xff0c;全面構建供應商全生命周期管理體系&#xff0c;以規范化、數智化推動采購生態向透明、高效、智能方向持續升級。 鄭州信源數智化招標采購系統研發商&#xff0c;通過供應商管理子系…

Fiori學習專題二十五:Remote OData Service

之前我們都是使用本地JSON來顯示發票清單。這節課我們將調用一個UI5公共的OData Service 1.由于本地開發訪問OData服務https://services.odata.org/V2/Northwind/Northwind.svc/會產生跨域問題&#xff0c;所以這里我們需要使用代理 新建一個終端&#xff1a;執行&#xff1a;n…

文件讀取操作

如果需要從文件讀入數據&#xff0c;并把輸出數據保存為文件&#xff0c;需要使用文件讀取。 freopen為file reopen&#xff0c;意為文件重新打開&#xff0c;實現重定向標準輸入輸出第一個參數為文件名可以修改&#xff0c;輸入文件為.in&#xff0c;輸出文件為.out第二個參數…

[Linux網絡_68] 轉發 | 路由(Hop by Hop) | IP的分片和組裝

目錄 1.再談網絡轉發 2.路由 舉個例子 3.分片和組裝 IP 層 [Linux#67][IP] 報頭詳解 | 網絡劃分 | CIDR無類別 | DHCP動態分配 | NAT轉發 | 路由器 1.再談網絡轉發 我們在上一篇文章中知道了路由器的功能有&#xff1a; 轉發DHCP | 組建局域網NAT 組建局域網功能表現&…

如何使用C語言手搓斐波那契數列?

斐波那契數列&#xff0c;第0項為0&#xff0c;第1項為1&#xff0c;第2項開始每項等于前兩之和。&#xff08;有些題目從第一項開始&#xff0c;第一項為1&#xff0c;第二項也為1&#xff09;。 運行時&#xff0c;輸入的n代表的是項數&#xff0c;而輸出則代表的是該項的值。…

java: 警告: 源發行版 21 需要目標發行版 21

解決這個問題看三個地方的SDK版本信息是否正確&#xff1a; 1&#xff0c;打開cmd命令&#xff0c;輸入 java -version ,查看版本是否正確&#xff1b; 2&#xff0c;打開模塊設置&#xff08;F4&#xff09;&#xff0c;查看項目的SDK 3&#xff0c;查看模塊的SDK

一區思路!挑戰5天一篇NHANES預測模型 DAY1-5

挑戰5天一篇預測模型NHANES Day1! 近期美國關閉seer數據庫的信息在互聯網上廣泛傳播&#xff0c;大家都在擔心數據庫挖掘是否還能做。這個問題其實是有答案的&#xff0c;數據庫挖掘肯定能做&#xff0c;做沒被關的數據庫即可&#xff0c;同時留意一些國產數據庫&#xff5e;…

centos7安裝NVIDIA顯卡

裝備工作 我的系統版本 cat /etc/centos-releaseCentOS Linux release 7.9.2009 (Core) 內核版本 rpm -q kernel或者 rpm -qa|grep kernelkernel-3.10.0-1160.el7.x86_64 注意以上輸出內核版本&#xff0c;按照我下面的操作步驟&#xff0c;不會出問題。否則重裝系統都有可…

Web應用開發指南

一、引言 隨著互聯網的迅猛發展&#xff0c;Web應用已深度融入日常生活的各個方面。為滿足用戶對性能、交互與可維護性的日益增長的需求&#xff0c;開發者需要一整套高效、系統化的解決方案。在此背景下&#xff0c;前端框架應運而生。不同于僅提供UI組件的工具庫&#xff0c…

Java @Transactional事物隔離級別和默認值詳解

在 Java 開發中&#xff0c;Transactional 注解是 Spring 框架中用于管理事務的重要工具。它提供了多種配置選項&#xff0c;其中事務隔離級別是一個關鍵屬性。本文將深入探討 Transactional 注解的隔離級別默認值&#xff0c;并通過具體代碼示例幫助你更好地理解和應用事務隔離…

車輛檢測新突破:VFM-Det 如何用大模型提升識別精度

目錄 ?編輯 一、摘要 二、引言 三、相關工作 四、Coovally AI模型訓練與應用平臺 五、方法 概述 綜述&#xff1a;基于區域建議的檢測 基于VehicleMAE的感知器 六、實驗分析 數據集與評估指標 實現細節 屬性預測模塊預訓練 與SOTA檢測器的對比實驗 消融實驗 V…

微格式:為Web內容賦予語義的力量

一、什么是微格式? 微格式是一種建立在已有 Web 標準基礎上的簡單、開放的數據格式。它的核心思想是通過在 HTML 標簽中添加特定的屬性和類名,為網頁內容添加語義注解,從而兼顧 HTML 文檔的人機可讀性。 簡單來說,微格式就是一套約定俗成的 HTML 標記方式,讓我們能夠在不…

偏移成像中,原始地震采集數據的數據規則化(Data Regularization)

在油氣地震資料處理中&#xff0c;柯希霍夫&#xff08;Kirchhoff&#xff09;積分法偏移成像對數據采集分布的均勻性較為敏感。當原始地震道數據存在空間分布不均勻時&#xff0c;會導致偏移噪聲、假頻或成像失真。數據規則化&#xff08;Data Regularization&#xff09;通過…

米殼AI:跨境電商圖片翻譯的“隱形革命”:當AI技術遇上全球化生意

一、行業觀察&#xff1a;跨境賣家的“語言圍城” 在亞馬遜西班牙站&#xff0c;某家居品牌因產品圖西班牙語翻譯錯誤導致整批貨物滯留港口&#xff1b;TikTok東南亞直播間里&#xff0c;美妝主播因馬來語字幕錯位引發消費者投訴……這些真實案例折射出跨境電商的集體困境&…

人工智能:如何將數據輸入到神經網絡中

文章目錄 引言數據輸入神經網絡的重要性及示例以識別美女圖片為例講解數據輸入不同應用的數據輸入方式結語 人工智能是引領未來的前沿技術領域。通過這個系統性學習計劃&#xff0c;我們將逐步深入如何將數據輸入到神經網絡中。無論你是初學者還是有一定基礎的開發者&#xff0…

數據庫12(游標)

游標語法 declare c1 cursor for select title from titles --定義一個游標c1&#xff0c;確定游標對應的列是titles表的title列&#xff0c;游標可以對應多個列 declare bname varchar(50) --聲明變量 open c1 --初始化&#xff0c;開始使用游標 fetch next from c1 in…

第四部分:賦予網頁健壯的靈魂 —— TypeScript(中)

目錄 4 類與面向對象&#xff1a;構建復雜的組件4.1 類的定義與成員4.2 繼承 (Inheritance)4.3 接口實現 (Implements)4.4 抽象類 (Abstract Class)4.5 靜態成員 (Static Members) 5 更高級的類型&#xff1a;讓類型系統更靈活5.1 聯合類型 (|)5.2 交叉類型 (&)5.3 字面量類…

Vue3源碼學習-提交限制

文章目錄 前言? 1. ESLint 限制&#x1f527; 配置位置&#xff1a;? 啟用了哪些規則&#xff08;核心&#xff09;&#xff1a;&#x1f4e6; 使用的插件和標準&#xff1a; ? 2. TSC 編譯限制關鍵選項&#xff1a; ? 3. Git Hook 校驗工具鏈配置例子&#xff08;package.…

Arthas 使用攻略

目錄 背景 Arthas是什么&#xff1f; 安裝 使用arthas-boot&#xff08;推薦&#xff09; 啟動 常用命令 一鍵生成arthas命令的插件(強烈推薦) watch 一、命令語法結構 二、核心參數詳解 三、實戰場景 1. 基礎觀測 - 查看入參和返回值 2. 條件過濾 - 只關注特定參…

冥想類短視頻批量剪輯自動混剪技術實踐:從素材處理到智能合成全解析

一、引言&#xff1a;工業化內容生產的技術突圍 在心理健康類內容爆發的當下&#xff0c;冥想類短視頻憑借「低制作成本 高用戶粘性」的特性成為熱門賽道。本文結合實戰經驗&#xff0c;解析如何通過模塊化素材處理、參數化合成引擎、自動化質量控制等技術手段&#xff0c;構…