首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

JVM 垃圾回收核心原理:從對象存活判定到分代收集算法

     編輯:關於C++

GC 回收什麼?

Java 記憶體模型中,程序計數器、虛擬機棧、本地方法棧隨線程生滅,棧幀隨方法出棧自動釋放,無需 GC 介入。
GC 核心針對:堆、方法區(類信息、常量、靜態變量)。這兩區內存分配動態,只有運行時才知創建哪些對象。

垃圾檢測算法

引用計數法

對象添加引用計數器,引用+1,釋放-1。
致命缺陷:無法處理循環引用(A→B,B→A,外部無引用,計數器永不歸零)。

可達性分析算法

以 GC Roots 為起點(棧局部變量、方法區靜態屬性/常量、本地方法棧 JNI 引用等),向下搜索引用鏈。
不可達對象 = 垃圾。採用 Dijkstra 著色算法(白/灰/黑),時間複雜度 O(n)。

垃圾回收算法

1. 標記-清除

標記垃圾 → 直接清除。
缺點:內存碎片化,大對象分配困難。

2. 複製算法

內存劃分為兩塊,每次只用一塊。GC 時將存活對象複製到另一塊,清空已用塊。
優點:無碎片、分配指針碰撞極快。
缺點:空間利用率 50%。
現代商業 JVM 新生代優化:Eden:Survivor = 8:1:1,實際可用 90%。

3. 標記-整理

標記垃圾 → 清除 → 存活對象向一端移動整理。
優點:無碎片、空間利用率高。
缺點:移動對象需更新引用,速度最慢,難以並發。

JVM 實際採用:分代收集算法

基於弱代假說:
① 大多數對象朝生夕死
② 熬過多次 GC 的對象難以消亡

堆劃分:

  • 新生代:Eden + 2 Survivor,採用複製算法
  • 老年代:存活率高,採用標記-整理或標記-清除
  • 持久代/元空間:類元數據,極少 GC

七大收集器在分代模型中的定位

收集器作用代算法線程特點
Serial新生代複製單Client默認,簡單高效
ParNew新生代複製多Serial多線程版,唯一配CMS
Parallel Scavenge新生代複製多關注吞吐量,自適應調節
Serial Old老年代標記-整理單Client老年代默認
Parallel Old老年代標記-整理多配合Parallel Scavenge
CMS老年代標記-清除多(並發)低停頓,碎片、浮動垃圾、CPU敏感
G1整堆(Region)標記-整理+複製多(並發+並行)可預測停頓,大堆首選

CMS 並發標記流程詳解

  1. 初始標記 (STW):標記 GC Roots 直接可達對象
  2. 並發標記:從 Roots 遍歷對象圖,耗時長但並發
  3. 重新標記 (STW):修正並發階段因應用線程導致的引用變動(增量更新/原始快照)
  4. 並發清除:清理不可達對象,並發進行

G1 Region 與 RSet 機制

  • 堆劃分為最多 2000 個 Region (1-32MB),邏輯上屬於 Eden/Survivor/Old
  • 每個 Region 維護 Remembered Set:記錄其他 Region 指向本 Region 的引用
  • GC 時只需掃描 RSet 而非全堆,實現 Region 級並行回收
  • 篩選回收:按 回收價值 = 可回收空間 / 回收耗時 排序,優先回收高價值 Region

總結

  1. 可達性分析解決循環引用問題,是現代 JVM 判定垃圾的基石
  2. 三大基礎算法各有優劣,分代收集將其組合發揮最大效能
  3. 收集器演進路線:串行 → 並行 → 並發 → 分區並發 (G1) → 低延遲可預測 (ZGC/Shenandoah)
  4. 調優核心:理解業務對停頓/吞吐敏感度,選擇合適收集器組合與堆大小
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved