JVM 垃圾回收機制深度解析(含圖解)

JVM 垃圾回收機制深度解析(含圖解)

一、垃圾回收整體流程

垃圾回收圖解

新生代Eden區
Eden區滿
達到閾值
未達閾值
老年代空間不足
程序運行
內存分配
對象創建
對象進入Eden區
新生代GC觸發條件
Minor GC(新生代回收)
存活對象復制到Survivor區
對象年齡增加
對象晉升到老年代
對象留在Survivor區
繼續使用Survivor區
對象進入老年代
老年代GC觸發條件
Major GC/Full GC(老年代回收)
標記-清除/整理老年代對象
釋放內存

二、垃圾對象判定算法

以下是對 JVM 垃圾回收機制的進一步細化,結合圖解直觀展示核心概念、算法流程及收集器工作原理:

2.1 引用計數法(Reference Counting)

對象創建
分配內存并初始化引用計數為1
其他對象引用該對象
引用計數+1
引用失效(如指針指向其他對象)
引用計數-1
引用計數是否為0?
對象標記為垃圾,等待回收
對象存活,繼續使用
垃圾回收器回收內存
重置內存狀態

原理:

  • 計數器管理

    • 每個對象內嵌一個引用計數器(Reference Counter)
    • 引用增加(如被賦值、作為參數傳遞) → 計數器+1
    • 引用失效(如變量置空、離開作用域) → 計數器-1
  • 回收條件

    • 當計數器歸零時,對象立即被標記為垃圾并回收。

循環引用問題: 無法處理循環引用(如對象 A 和 B 互相引用),導致內存泄漏。

A對象
B對象

場景描述:

對象A和B互相引用,導致兩者的引用計數始終≥1,即使它們已不被其他對象引用,也無法被回收。后果:內存泄漏(Memory Leak)。

解決循環引用的常見方法

  • 弱引用(Weak Reference)

    弱引用不增加對象的引用計數(如Java的WeakReference、Python的weakref)。

  • 手動斷開引用

    開發者需在代碼中顯式解除循環引用(易出錯,不推薦)。

  • 周期檢測算法

    定期運行垃圾回收器檢測循環引用(如Python的gc模塊)。

2.2 可達性分析(Reachability Analysis)

可達性分析示意圖

可達性分析完整流程
三色標記法核心流程
白色
灰色/黑色
所有堆對象初始為白色(隱式狀態)
開始可達性分析
標記GC Roots
遍歷GC Roots直接引用對象
標記完成
所有白色對象為垃圾
執行垃圾回收
灰色隊列是否為空?
標記直接引用對象為灰色
取出一個灰色對象
遍歷其引用的子對象
子對象顏色?
標記子對象為灰色并加入隊列
跳過處理
當前對象標記為黑色

原理:
從一組稱為GC Roots的根對象出發,沿著引用鏈向下搜索,所有能被訪問到的對象視為“存活”,未被訪問的則判定為“不可達”對象,可被回收。

整體結構

外層是可達性分析的主流程,內嵌三色標記法的核心流程。

顏色標識統一:

白色:未處理或可回收對象(最終狀態)
灰色:待處理對象(中間狀態)
黑色 :已處理完成對象
紅色邊框:垃圾回收相關操作

關鍵流程節點

  • 標記GC Roots: 從GC Roots(根對象如棧、靜態變量等)出發,遞歸遍歷所有可達對象,將其直接引用的堆對象標記為灰色,并加入灰色隊列,作為標記的起點。

  • 三色標記循環: 通過灰色隊列迭代處理對象(白→灰→黑狀態變化)。

    1. 取出灰色對象,遍歷其引用的子對象;
    2. 若子對象為白色,標記為灰色并加入隊列;
    3. 當前灰色對象標記為黑色;
    4. 重復直到灰色隊列為空。”
  • 回收階段: 清除所有白色(未被標記/不可達)對象,釋放內存。

顏色狀態映射

存活對象標記流程:
GC Roots → 白色 → 灰色 → 遍歷引用 → 黑色(完成)垃圾對象:
始終為白色 → 最終被回收

可達性分析的優勢

  • 解決循環引用問題
    即使對象A和對象B互相引用,若它們無法從GC Roots到達,仍會被判定為垃圾。

  • 高效性
    通過引用鏈遍歷,僅需處理存活對象,避免全堆掃描。

并發標記的挑戰
在并發標記階段(如CMS、G1回收器),用戶線程可能修改對象引用,導致兩種問題:

  • 漏標(Missing Mark)

    • 增量更新(Incremental Update)

      若黑色對象新增對白色對象的引用,將該黑色對象重新標記為灰色(需重新掃描)。

    • 原始快照(SATB)

      記錄標記開始時的對象引用關系,后續新增的引用關系視為“待處理”。

  • 多標(Floating Garbage)

    • 已標記為存活的對象被用戶線程置為不可達(通常容忍到下次GC處理)。

GC Roots 包括:
1. 虛擬機棧(Java 棧)中的引用對象
來源: 方法執行時,棧幀中局部變量表存儲的引用類型變量。
生命周期: 與方法調用綁定,方法結束后引用失效。
示例:

public void method() {Object obj = new Object(); // obj 是 GC Root// 方法執行期間,obj 引用的對象不會被回收
} // 方法結束后,obj 出棧,對象失去 GC Root 引用

2. 方法區中靜態屬性引用的對象
來源: 類的靜態變量(static 字段)。
生命周期: 與類的生命周期相同,類卸載前始終存活。
示例:

public class MyClass {static Object staticObj = new Object(); // staticObj 是 GC Root
}

3. 方法區中常量引用的對象
來源: 字符串常量池(String Table)、類常量(final static)等。
示例:

public class Constants {public static final String NAME = "Doubao"; // "Doubao" 是 GC Rootpublic static final List<String> LIST = Collections.unmodifiableList(Arrays.asList("a", "b") // 列表對象是 GC Root);
}

4. 本地方法棧中 JNI 引用的對象
來源: Java 調用本地代碼(如 C/C++)時,本地方法棧中保存的引用。
示例:

public native void nativeMethod(); // 本地方法可能持有對象引用,成為 GC Root

5. 其他特殊引用

  • 活動線程(Active Threads):
Thread thread = new Thread(() -> {Object obj = new Object(); // obj 被線程棧引用,成為 GC Root// ...
});
thread.start();
  • 類加載器(ClassLoader):
加載的類和靜態變量。
  • JVM 內部對象:
如系統類(java.lang.Class)、異常對象(ThreadDeath)等。

GC Roots 內存示意圖

GC Roots
引用
引用
引用
引用
棧幀中變量
不可達
對象1
虛擬機棧局部變量
對象2
靜態變量
對象3
常量
對象4
本地方法JNI引用
對象5
活動線程
對象6
對象7
對象8
無GC Root引用的對象
垃圾回收

三、垃圾回收算法詳解

3.1 標記 - 清除(Mark-Sweep)

開始GC
標記存活對象(藍色)
清除未標記對象(灰色)
釋放內存空間(白色)
產生內存碎片(不連續的綠色區域)

步驟:
1. 標記: 在堆中遍歷所有對象,找出內存中需要回收的對象,并且把它們標記出來。

(藍色為存活對象、灰色為可回收對象、白色為可用內存)
在這里插入圖片描述

2. 清除: 清除掉被標記需要回收的對象,釋放出對應的內存空間。

在這里插入圖片描述

缺點:

  • 效率低: 兩次遍歷堆,耗時較長。
  • 內存碎片: 回收后產生不連續內存塊,可能導致大對象分配失敗。

3.2 復制(Copying)

開始GC
將Eden+Survivor區存活對象復制到To Survivor
清空Eden+From Survivor (s0)區
交換From和To Survivor (s1) 區角色
繼續使用新的Eden+From區

步驟:

  • 將內存分為Eden 區和兩個Survivor 區(通常比例 8:1:1)。
  • 新對象分配到 Eden 區,當 Eden 區滿時觸發 Minor GC。
  • 存活對象復制到 From Survivor (s0) 區,清空 Eden 區。
  • 下次 GC 時,將 Eden+ From Survivor (s0) 的存活對象復制到 To Survivor (s1) 區,清空原區域。
  • 經歷多次 GC 仍存活的對象晉升到老年代。

圖解:

  1. 將內存劃分為兩塊相等的區域,每次只使用其中一塊

(藍色為存活對象、灰色為可回收對象、白色為可用內存、綠色為保留內存)
在這里插入圖片描述
3. 當其中一塊內存使用完了,就將還存活的對象復制到另外一塊上面,然后把已經使用過的內存空間一次清除掉。

在這里插入圖片描述

優點: 無內存碎片,效率高(只需移動指針)。
缺點: 浪費 50% 內存空間(實際采用 8:1:1 比例,僅浪費 10%)。


3.3 標記 - 整理(Mark-Compact)

開始GC
標記存活對象
將存活對象向一端移動
清理邊界外的內存
無內存碎片

步驟:

  • 標記: 遍歷標記存活對象(灰色)。
  • 整理: 將存活對象向一端移動,直接清理邊界外的內存(白色區域)。
  • 優點: 無內存碎片,適合對象存活率高的場景(如老年代)。

圖解:

  1. 標記過程仍然與 標記-清除算法 一樣,但是后續步驟不是直接對可回收對象進行清理,
    而是讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存。

(藍色為存活對象、灰色為可回收對象、白色為可用內存)
在這里插入圖片描述

  1. 讓所有存活的對象都向一端移動,清理掉邊界以外的內存。

在這里插入圖片描述

缺點: 需移動對象,成本較高。


3.4 分代收集(Generational Collection)

新對象創建
分配到Eden區
Eden區滿?
觸發Minor GC
繼續分配
存活對象復制到From Survivor (s0) 區
清空Eden區
對象年齡+1
年齡達到閾值?
晉升到老年代
對象留在From Survivor (s0) 區
下次Minor GC
存活對象復制到To Survivor (s1) 區
清空Eden+From Survivor (s0) 區
交換Survivor1和To Survivor (s1) 區角色
對象進入老年代
老年代空間不足?
觸發Major GC/Full GC
標記-清除/整理老年代對象
釋放老年代內存

原理:
根據對象存活周期將堆分為新生代和老年代:

  • 新生代(Eden+Survivor): 對象存活率低,采用 復制算法
  • 老年代: 對象存活率高,采用 標記 - 清除標記 - 整理算法
  • 永久代 / 元空間: 存儲類信息、常量池等,GC 頻率低。

四、垃圾收集器詳解

以下是 Java 主流垃圾回收器的核心啟動參數及典型配置
分代收集器分區收集器 分類整理:

I、分代收集器

4.1 Serial 收集器
觸發GC
Stop The World
初始標記(標記GC Roots直接引用的對象)
根搜索(遞歸遍歷所有可達對象)
標記所有存活對象
清除未標記對象(回收垃圾)
內存空間整理(可選)
恢復應用線程
繼續執行用戶程序

特點: 單線程,STW(Stop The World)【全程暫停用戶應用程序】,采用復制算法。

算法:

  • 新生代:復制算法(Copying)
    將存活對象從Eden區和Survivor區復制到另一個Survivor區,清除未存活對象。

  • 老年代:標記-整理算法(Mark-Compact)
    標記存活對象后,整理內存空間,消除碎片。

適用場景:

單線程環境(Client 模式),客戶端模式或小內存應用。

參數:

# 新生代和老年代均使用Serial(單線程)
-XX:+UseSerialGC -Xmx512m

4.2 Parallel Scavenge 收集器(吞吐量優先)
觸發GC
Stop The World
多線程初始標記(標記GC Roots直接引用的對象)
多線程根搜索(并行遍歷所有可達對象)
標記所有存活對象
多線程復制存活對象到Survivor區或老年代
清空Eden區和From Survivor區
交換From和To Survivor區角色
恢復應用線程
繼續執行用戶程序

特點: 多線程,關注吞吐量(運行用戶代碼時間 / 總時間)。
算法:

  • 新生代(Parallel Scavenge):復制算法
    多線程并行復制存活對象,提升回收效率。

  • 老年代(Parallel Old):標記-整理算法
    多線程并行標記和整理,減少碎片。

適用場景:

多核服務器,注重吞吐量而非低延遲。

參數


# 新生代Parallel Scavenge + 老年代Parallel Old
-XX:+UseParallelGC -XX:+UseParallelOldGC -Xmx4g # 控制最大停頓時間(毫秒)
-XX:MaxGCPauseMillis=100 # 控制吞吐量目標(默認99%)(如 99 表示 1% 時間用于 GC)。
-XX:GCTimeRatio=99# 自適應調整內存區域大小
-XX:+UseAdaptiveSizePolicy 

4.3 CMS(Concurrent Mark Sweep)收集器(低延遲)
開始CMS GC
初始標記(STW)
并發標記
重新標記(STW)
并發清除
完成GC,恢復用戶線程

算法:

  • 標記-清除算法(Mark-Sweep)
  • 工作流程:
    1. 初始標記(STW,短暫):標記 GC Roots 直接關聯的對象。
    2. 并發標記:與用戶線程并發執行,遍歷可達對象。
    3. 重新標記(STW):修正并發標記階段因用戶線程運行導致的對象引用變化(使用增量更新算法)。
    4. 并發清除:與用戶線程并發未標記對象。

缺點:

  • 內存碎片: 標記-清除算法不整理內存,長期運行后碎片化嚴重,可能導致:

    • 晉升失敗(Promotion Failed): 新生代對象無法晉升到老年代。

    • 大對象分配失敗(Humongous Allocation Failure)。

    • 最終觸發 Full GC,使用 Serial Old(標記-整理算法) 壓縮內存。

        CMS的核心目標是通過標記-清除算法減少垃圾回收的停頓時間(STW)。然而,由于其設計上的限制,CMS在某些場景下觸發Full GC,無法通過并發操作完成垃圾回收,此時JVM會觸發故障回退機制(Fallback Mechanism),強制使用單線程的Serial Old收集器(標記-整理算法)進行壓縮執行Full GC以恢復內存可用性。這種設計是CMS在低延遲與內存連續性之間的權衡。
      
  • 吞吐量下降: 并發階段占用 CPU 資源,與用戶線程競爭。

  • 無法處理突發分配壓力: 并發周期中若老年代空間不足,觸發并發模式失敗(Concurrent Mode Failure)。

觸發Full GC的場景描述是否使用Serial Old
并發模式失敗并發標記期間老年代空間不足
晉升失敗新生代對象晉升到老年代時因碎片無法分配
顯式調用System.gc()強制觸發Full GC(默認開啟ExplicitGCInvokesConcurrent可繞過此行為)
元空間耗盡類元數據區無法擴展
其他內存分配失敗直接內存(Direct Memory)或本地內存(Native Memory)耗盡等
觸發條件: 并發模式失敗/晉升失敗等
STW: 終止并發操作
啟動Serial Old收集器
標記階段: 標記存活對象
整理階段: 移動對象消除碎片
清除階段: 回收垃圾內存
恢復用戶線程

適用場景

Web 服務器、需要快速響應的應用、老年代垃圾回收、追求低停頓時間。

參數

# 新生代ParNew + 老年代CMS
-XX:+UseConcMarkSweepGC -Xmx8g # 老年代使用70%時觸發CMS(默認92%)
-XX:CMSInitiatingOccupancyFraction=70# 控制Full GC時是否進行內存壓縮(減少碎片)(標記-整理)。
-XX:+UseCMSCompactAtFullCollection# 并行執行重新標記階段
-XX:+CMSParallelRemarkEnabled# 指定經過多少次Full GC后執行一次壓縮(0表示每次Full GC都壓縮)。
-XX:CMSFullGCsBeforeCompaction=0    

II、分區收集器

4.4 G1(Garbage-First)收集器(區域化、平衡延遲與吞吐量)
開始G1 GC
初始標記(STW)
并發標記
最終標記(STW)
篩選回收(STW)
根據停頓時間選擇Region回收
復制存活對象到新Region
清空回收的Region
繼續執行用戶線程

算法:

  • 分區(Region)
    將堆劃分為多個大小相等的 Region(如 2MB-32MB)。

  • 新生代:復制算法
    存活對象復制到Survivor Region或晉升到老年代Region。

  • 老年代:標記-整理算法
    并發標記后,優先回收垃圾最多的Region(Garbage-First),并整理Region內空間。

  • 動態分代
    每個 Region 可動態扮演 Eden、Survivor、Old 或 Humongous(大對象)。

  • 可預測停頓
    根據 Region 的回收價值(垃圾占比)排序,優先回收收益高的區域。

  • 工作流程
    1. 初始標記(STW 極短): 標記 GC Roots 直接關聯的 Region。
    2. 并發標記: 與用戶線程并發標記存活對象。
    3. 最終標記(STW): 處理并發階段的增量更新(使用 SATB 快照算法)。
    4. 篩選回收(STW): 根據停頓時間目標選擇 Region 進行回收,采用復制算法。

關鍵說明:
G1 設計上通過 Mixed GC(混合回收) 避免 Full GC,但在極端情況(如并發標記失敗)下仍可能觸發 Full GC,此時 觸發故障回退機制(Fallback Mechanism) 到單線程的 Serial Old收集器(標記-整理算法)

  • 觸發條件: 堆內存不足且無法通過 Mixed GC 回收足夠空間。
  • 優化建議: 通過 -XX:G1ReservePercent 增加預留內存,降低 Full GC 概率。

適用場景:

大堆內存(數十GB至數百GB)、追求低延遲與吞吐量平衡的應用。

參數:

# 啟用G1收集器(JDK 9+默認)
-XX:+UseG1GC -Xmx16g# 設置最大停頓時間目標(毫秒)
-XX:MaxGCPauseMillis=200# 設置Java堆區域大小(默認2的冪,1-32MB)
-XX:G1HeapRegionSize=8m# 老年代占用50%時啟動混合回收
-XX:InitiatingHeapOccupancyPercent=50
#  G1 垃圾收集器預留堆內存的百分比,默認值:10(即預留 10% 的堆內存)
-XX:G1ReservePercent=10

4.5 ZGC收集器(Z Garbage Collector)(超低延遲,JDK 11+)
開始ZGC
初始標記(極短STW)
并發標記
再標記(極短STW)
并發轉移準備
并發轉移(通過讀屏障修正引用)
完成GC,幾乎無STW

特點:

  • 著色指針(Colored Pointers)
    將 GC 信息(Marked0/1、Remapped)存儲在指針的低 4 位,無需掃描對象頭。

  • 讀屏障(Load Barrier)
    在讀取對象引用時動態修正指針,實現并發移動。

  • 并發整理
    全程幾乎無 STW(僅初始標記和再標記有極短停頓,通常 < 1ms)。

適用場景:

超大堆內存(TB 級),追求極致低延遲(<10ms),如金融交易系統。

算法:

  • 并發標記-整理算法(Concurrent Mark-Compact)

    1. 并發標記: 利用染色指針(Colored Pointers)標記對象狀態。

    2. 并發預備重分配: 確定需要清理的內存區域。

    3. 并發重分配: 將存活對象復制到新地址,并更新引用。

    4. 并發重映射: 修復舊地址到新地址的映射。

    5. 關鍵技術: 染色指針和讀屏障,支持全階段并發執行。

參數:

# 啟用ZGC(需JDK 11+)
-XX:+UseZGC -Xmx32g # 設置最大堆大小(ZGC適合大內存)
-Xmx64g -Xms64g# 設置并發GC線程數(默認CPU核心數的1/4)
-XX:ConcGCThreads=4# 配置GC周期的最大停頓時間(目標值)
-XX:MaxGCPauseMillis=10

4.6 Shenandoah收集器(超低延遲,OpenJDK 12+)
觸發GC
初始標記(STW)
并發標記
最終標記(STW)
并發回收準備
并發對象轉移
引用修正(讀屏障)
并發清理
完成GC,恢復應用線程

特點:

  • 與 ZGC 類似,基于轉發指針和布魯姆過濾器實現并發回收,停頓時間極短。

適用場景:

OpenJDK 環境下的超大堆內存(TB級)、極低停頓時間(亞毫秒級)、低延遲應用。

算法:

  • 并發復制算法(Concurrent Copying)

    1. 并發標記: 與用戶線程并發標記存活對象。

    2. 并發預清理: 確定需要回收的Region。

    3. 并發轉移: 在用戶線程運行時,將存活對象復制到新Region。

    4. 引用更新: 并發更新對象引用至新地址。

    5. 關鍵技術: 使用 讀屏障(Read Barrier) 實現并發對象移動。

參數:

# 啟用Shenandoah(需JDK 12+,OpenJDK默認包含)
-XX:+UseShenandoahGC -Xmx16g # 設置GC策略(normal/size/reference-time)
-XX:ShenandoahGCHeuristics=normal# 設置最大停頓時間目標(毫秒)
-XX:MaxGCPauseMillis=100

III、垃圾收集器對比表

收集器新生代算法老年代算法Full GC 收集器JDK版本支持默認收集器(JDK版本)推薦堆大小吞吐量適用場景是否開源所屬JVM實現垃圾對象判定算法核心特點
Serial復制標記-整理Serial Old(標記-整理)JDK 1.0+JDK 1.0~8(客戶端模式)<512MB客戶端應用、嵌入式系統HotSpot可達性分析(迭代標記)單線程簡單高效,無多線程開銷
Parallel復制標記-整理Parallel Old(標記-整理)JDK 1.4+JDK 8(服務器模式)512MB~32GB批處理、計算密集型任務HotSpot可達性分析(并行標記)多線程并行回收,最大化吞吐量
CMS復制(ParNew)標記-清除Serial Old(標記-整理)JDK 1.5~JDK14 (JDK 9+ 標記為廢棄,JDK 14+ 移除)無(需手動啟用)512MB~4GB低延遲Web服務(中小堆)HotSpot可達性分析(三色標記 + 增量更新)低延遲,并發標記減少停頓,但需監控碎片問題
G1復制標記-整理(分Region)Serial Old(標記-整理)JDK 7u4+JDK 9+(服務器模式)4GB~64GB中~高大堆內存、平衡型應用HotSpot可達性分析(三色標記 + SATB快照)分區回收,可預測停頓,自動整理碎片
ZGC并發復制并發標記-整理無(無 Full GC 概念)OpenJDK 11+JDK 15+(可選)≥4GB超大堆、亞毫秒級停頓HotSpot可達性分析(并發三色標記 + 染色指針)超大堆,染色指針,停頓<1ms
Shenandoah并發復制并發復制無(無 Full GC 概念)OpenJDK 12+無(需手動啟用)≥4GB超大堆、極低延遲需求HotSpot可達性分析(并發三色標記 + 讀屏障)全堆并發,停頓<10ms

IIII、垃圾對象判定算法詳解

收集器判定算法實現
Serial遞歸遍歷GC Roots,標記可達對象(無并發優化)。
Parallel多線程并行遍歷GC Roots,標記可達對象。
CMS三色標記法 + 增量更新(將修改引用的黑色對象重新標記為灰色)。
G1三色標記法 + SATB(原始快照)(基于標記開始時的引用關系進行標記)。
ZGC并發三色標記法 + 染色指針(通過指針元數據記錄對象狀態)。
Shenandoah并發三色標記法 + 讀屏障(攔截對象訪問,處理并發標記中的引用變化)。

五、GC 日志分析與可視化工具

獲取GC日志
分析GC類型(Minor/Full)
提取停頓時間
計算吞吐量
分析內存使用趨勢
定位頻繁GC原因
確定是否存在內存泄漏
調整堆大小/收集器參數
驗證優化效果

5.1 典型 GC 日志示例

[GC (Allocation Failure) [PSYoungGen: 524288K->1024K(524288K)] 524288K->1025K(1048576K), 0.0012345 secs]

解析:

  • GC:新生代 GC。
  • Full GC:整堆 GC。
  • Allocation Failure:因內存分配失敗觸發 GC。
  • PSYoungGen:Parallel Scavenge 收集器的新生代。
  • 524288K->1024K:回收前→回收后的內存使用量。
  • 0.0012345 secs:GC 耗時。

5.2 可視化工具推薦

  • GCViewer:解析 GC 日志,生成可視化圖表(如停頓時間、內存使用趨勢)。
  • GCEasy:在線工具,上傳 GC 日志后提供詳細分析報告和優化建議。
  • JProfiler:集成 GC 分析功能,支持實時監控和堆轉儲分析。
  • Java Mission Control (JMC):Oracle 官方工具,提供高性能監控和診斷。
  • Arthas(阿爾薩斯):阿里巴巴開源的 實時診斷工具,通過命令行或 Web UI 動態監控和排查問題。
  • VisualVM:輕量級可視化工具,集成多種性能分析功能(含 GC 監控),支持插件擴展。

六、性能調優實戰案例

6.1 高并發 Web 應用調優

場景: 8 核 16GB 服務器,Tomcat 應用,響應時間敏感。
配置:

java -Xms8g -Xmx8g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
-XX:G1HeapRegionSize=8m \
-XX:+ParallelRefProcEnabled \
-jar app.jar

效果:

  • 新生代 GC 頻率降低,停頓時間控制在 50ms 以內。
  • 老年代碎片化問題緩解,Full GC 頻率從每天數次降為每周一次。

6.2 大數據批處理調優

場景: Spark 作業,64GB 內存,追求高吞吐量。
配置:

spark-submit --conf spark.executor.memory=48g \
--conf spark.executor.extraJavaOptions="-XX:+UseParallelGC -XX:GCTimeRatio=99" \
--class com.example.BatchJob app.jar

效果:

  • 吞吐量提升 20%,GC 時間占比從 5% 降至 1%。
  • 并行 GC 充分利用多核 CPU,減少 STW 時間。

七、總結與最佳實踐

垃圾判定:優先使用可達性分析,避免引用計數法的循環引用問題。
算法選擇

  • 新生代:對象存活率低→復制算法。
  • 老年代:對象存活率高→標記 - 整理算法。

收集器選型

<=4GB
4GB-16GB
高吞吐量
低延遲
>16GB
高吞吐量
低延遲
選擇垃圾收集器
堆內存大小
Serial/Parallel
延遲要求
Parallel+Parallel Old
CMS/G1
延遲要求
Parallel+Parallel Old
是否需要商業支持
ZGC
Shenandoah
CMS(老年代)+ ParNew(新生代)
G1
適用于老年代對象存活率高、允許一定碎片的場景
適用于大內存、追求平衡的場景
  • 小內存 / 單線程:Serial。
  • 吞吐量優先:Parallel。
  • 低延遲:CMS(老年代)、G1(大內存)、ZGC/Shenandoah(超大內存)。

性能監控:

  • 定期分析 GC 日志,監控停頓時間和內存使用趨勢。
  • 使用可視化工具定位內存泄漏和大對象問題。

通過結合圖解和實戰案例,可更直觀地理解 JVM 垃圾回收機制的底層原理,從而針對性地優化應用性能。

附:

  • JVM圖解
本地方法接口
執行引擎
Java虛擬機運行時數據區
類加載子系統
垃圾回收器
方法區(線程共享)
堆內存(線程共享)
虛擬機棧(線程私有)
程序計數器(線程私有)
鏈接(Linking)
啟動類加載器
擴展類加載器
系統類加載器
對象分配
對象分配
晉升
晉升
本地方法庫
JNI
操作系統資源
逐行解釋字節碼
解釋器
中間代碼生成器
即時編譯器
代碼優化器
目標代碼生成器
新生代GC
GC管理器
老年代GC
垃圾回收器分類
Serial
新生代收集器
ParNew
Parallel Scavenge
老年代收集器
Serial Old
Parallel Old
CMS
混合收集器
G1
ZGC
Shenandoah
本地方法存儲
本地方法棧(線程私有)
線程A計數器
線程B計數器
棧幀
線程A
局部變量表
操作數棧
動態鏈接
方法返回地址
附加信息
棧幀
線程B
Eden
新生代
Survivor0
Survivor1
老年代
類元信息
方法元信息
運行時常量池
靜態變量
加載
.class文件
初始化
準備
驗證
解析
  • ??運行時數據區的初始化時機
運行時數據區初始化時機與類加載的關系
方法區JVM 啟動時分配內存,類加載時寫入類元信息、常量池、靜態變量等。類加載的初始化階段會向方法區寫入靜態變量。
JVM 啟動時分配內存,對象實例在 new 時創建。類初始化完成后,通過 new 觸發對象分配。
虛擬機棧線程創建時初始化,每個線程有獨立棧空間,棧幀在方法調用時動態生成。與類加載無關,由線程執行引擎管理。
程序計數器線程創建時初始化,記錄當前執行指令地址。與類加載無關,由線程執行引擎管理。
本地方法棧線程創建時初始化,存儲本地方法(Native Method)調用信息。與類加載無關,由本地方法接口(JNI)管理。
  • 類加載與運行時數據區的關系
運行時數據區
類加載子系統
寫入
觸發對象創建
方法調用時創建棧幀
虛擬機棧
本地方法棧
程序計數器
初始化
鏈接
加載
方法區
棧幀
局部變量表
操作數棧

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

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

相關文章

MySQL快速入門篇---聯合查詢

一、什么是聯合查詢 1.1、概念 聯合查詢是SQL中用于合并多個SELECT語句結果集的操作。條件是被合并的結果集列數相同并且數據類型兼容。也可以說一次查詢涉及兩張或兩張以上的表&#xff0c;就稱為聯合查詢。 1.2、為什么要使用聯合查詢 如果數據被拆分到多個表中&#xff…

Spring Boot AI 之 Chat Client API 使用大全

ChatClient提供了一套流暢的API用于與AI模型交互,同時支持同步和流式兩種編程模型。 流暢API包含構建Prompt組成元素的方法,這些Prompt將作為輸入傳遞給AI模型。從API角度來看,Prompt由一系列消息組成,其中包含指導AI模型輸出和行為的指令文本。 AI模型主要處理兩類消息: …

基于點標注的弱監督目標檢測方法研究

摘要 在計算機視覺領域&#xff0c;目標檢測需要大量精準標注數據&#xff0c;但人工標注成本高昂。弱監督目標檢測通過低成本標注訓練模型&#xff0c;成為近年研究熱點。本文提出一種基于點標注的弱監督目標檢測算法&#xff0c;僅需在圖像中物體中心點標注&#xff0c;即可高…

外網如何連接內網中的mysql數據庫服務器?簡單網絡工具方案

當內網服務器部署好mysql數據庫后&#xff0c;在局域網外需要用程序進行mysql 遠程訪問&#xff0c;而mysql因為安全的因素&#xff0c;默認的時候用戶設置的是不能遠程連接&#xff0c;只能本地連接&#xff0c;這個時候就需要自己去修改其中的設置。下面就介紹一下相關mysql的…

無人機避障——深藍學院浙大柵格地圖以及ESDF地圖內容

Occupancy Grid Map & Euclidean Signed Distance Field: 【注意】&#xff1a;目的是為了將有噪聲的傳感器收集起來&#xff0c;用于實時的建圖。 Occupancy Grid Map&#xff1a; 概率柵格&#xff1a; 【注意】&#xff1a;由于傳感器帶有噪聲&#xff0c;在實際中基于…

Rocky Linux 8.9 升級至 8.10 測試可通過以下步驟完成

一、執行升級? sudo dnf -y update --disablerepoappstream 二、重啟系統? reboot ?三、驗證升級結果? ?檢查系統版本? 執行命令確認版本已更新 cat /etc/redhat-release 輸出應包含 Rocky Linux release 8.10

固定翼無人機拋投技術分析!

一、技術要點 1. 結構設計優化 傳動組件創新&#xff1a;采用齒輪-齒條傳動&#xff08;替代傳統絲桿結構&#xff09;&#xff0c;簡化機械設計&#xff0c;降低成本并提高可靠性。例如&#xff0c;通過電機驅動齒輪帶動齒條移動&#xff0c;實現柱銷與拋投物插孔的精準分…

Oracle中的[行轉列]與[列轉行]

目錄 一、原始數據 二、行轉列的多種實現方式 1.CASE WHEN 2.DECODE 3.PIVOT(Oracle獨有) 4.使用LEAD開窗函數 三、列轉行的多種實現方式 1.UNPIVOT(Oracle獨有) 2.UNION ALL合并結果集 四、行轉列練習&#xff1a;CASE WHEN/DECODE/PIVOT/lag/LEAD 1.CASE WHEN 2…

【Excel VBA 】窗體控件分類

一、Excel 窗體控件分類 Excel 中的窗體控件分為兩大類型&#xff0c;適用于不同的開發需求&#xff1a; 類型所在選項卡特點表單控件開發工具 → 插入 → 表單控件簡單易用&#xff0c;直接綁定宏&#xff0c;兼容性好&#xff0c;適合基礎自動化操作。ActiveX 控件開發工具…

[ 計算機網絡 ] 深入理解OSI七層模型

&#x1f389;歡迎大家觀看AUGENSTERN_dc的文章(o゜▽゜)o☆?? &#x1f389;感謝各位讀者在百忙之中抽出時間來垂閱我的文章&#xff0c;我會盡我所能向的大家分享我的知識和經驗&#x1f4d6; &#x1f389;希望我們在一篇篇的文章中能夠共同進步&#xff01;&#xff01;&…

線性代數之張量計算,支撐AI算法的數學原理

目錄 一、張量計算的數學本質 1、線性代數:張量的幾何與代數性質 2、微積分:梯度與自動微分 3、優化理論:張量分解與正則化 4、張量計算的核心操作 二、張量計算在AI算法中的作用 1、數據表示與處理 2、神經網絡的參數表示 3、梯度計算與優化 三、張量計算在AI中的…

打造一個支持MySQL查詢的MCP同步插件:Java實現

打造一個支持MySQL查詢的MCP同步插件&#xff1a;Java實現 用Java實現一個MCP本地插件&#xff0c;直接通過JDBC操作本地MySQL&#xff0c;并通過STDIO與上層MCP客戶端&#xff08;例如Cursor&#xff09;通信。插件注冊一個名為mysql 的同步工具&#xff0c;接收連接參數及SQL…

【數據架構01】數據技術架構篇

? 9張高質量數據架構圖&#xff1a;大數據平臺功能架構、數據全生命周期管理圖、AI技術融合架構等&#xff1b; &#x1f680;無論你是數據架構師、治理專家&#xff0c;還是數字化轉型負責人&#xff0c;這份資料庫都能為你提供體系化參考&#xff0c;高效解決“架構設計難、…

java三種常見設計模式,工廠、策略、責任鏈

設計模式實戰解析 一、工廠模式&#xff08;點外賣模式&#xff09; 1. 核心思想 代替直接new對象像點外賣一樣獲取對象 2. 實際應用 Spring框架&#xff1a;BeanFactoryJDBC&#xff1a;DriverManager.getConnection() 3. 三種變體對比 類型特點示例場景簡單工廠一個工…

jenkins使用Send build artifacts over SSH發布jar包目錄配置

本測試用ruoyi-plus的代碼。 1 [GitLab 自動觸發 Jenkins 構建_jenkins構建觸發器沒有build when a change is pushed to git-CSDN博客](https://blog.csdn.net/wangyiyungw/article/details/81776972) 2 [jenkins使用Send build artifacts over SSH遇到的坑-CSDN博客](https…

vscode打開vue + element項目

好嘞&#xff0c;我幫你詳細整理一個用 VS Code 來可視化開發 Vue Element UI 的完整步驟&#xff0c;讓你能舒服地寫代碼、預覽界面、調試和管理項目。 用 VS Code 可視化開發 Vue Element UI 全流程指南 一、準備工作 安裝 VS Code 官網下載安裝&#xff1a;https://code…

黑馬程序員C++2024新版筆記 第4章 函數和結構體

目錄 1.結構體的基本應用 2.結構體成員的默認值 3.結構體數組 4.結構體指針 ->操作符 5.結構體指針數組 1.引入已存在的結構體數組地址 2.通過new操作符申請指針數組空間 6.函數的概念 7.函數的基礎語法 8.無返回值函數和void類型 9.空參函數 10.函數的嵌套調用…

高級前端工程師必備的 JS 設計模式入門教程,常用設計模式案例分享

目錄 高級前端工程師必備的 JS 設計模式入門教程&#xff0c;常用設計模式案例分享 一、什么是設計模式&#xff1f;為什么前端也要學&#xff1f; 1、設計模式是什么 2、設計模式的產出 二、設計模式在 JS 里的分類 三、常用設計模式實戰講解 1、單例模式&#xff08;S…

Ubuntu+Docker+內網穿透:保姆級教程實現安卓開發環境遠程部署

文章目錄 前言1. 虛擬化環境檢查2. Android 模擬器部署3. Ubuntu安裝Cpolar4. 配置公網地址5. 遠程訪問小結 6. 固定Cpolar公網地址7. 固定地址訪問 前言 本文將詳細介紹一種創新性的云開發架構&#xff1a;基于Ubuntu系統構建Android仿真容器環境&#xff0c;并集成安全隧道技…

Linux Kernel調試:強大的printk(一)

引言 想了好久&#xff0c;還是覺得這個標題才配得上printk&#xff01;^_^ 我相信&#xff0c;不管做什么開發&#xff0c;使用最多的調試手段應該就是打印了&#xff0c;從我們學習編程語言第一課開始&#xff0c;寫的第一段代碼&#xff0c;就是打印"Hello, world&qu…