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

JVM 記憶體模型與垃圾回收機制深度解析

     編輯:Java 相關知識

JVM 運行時資料區域

Java 虛擬機在執行程式時會將記憶體劃分為若干區域,每個區域有特定用途與生命週期:

區域線程共享性主要內容OOM 風險
程式計數器線程私有當前執行的位元碼指令地址無
Java 虛擬機棧線程私有棧幀(局部變數表、操作數棧、動態連結、方法返回地址)StackOverflowError / OOM
本地方法棧線程私有Native 方法調用狀態StackOverflowError / OOM
堆線程共享物件實例、陣列、字串常量池(JDK 7+)OOM
方法區線程共享類元資料、常量、靜態變數、即時編譯器代碼緩存OOM
直接記憶體不受 JVM 直接管理NIO DirectBuffer、Native 分配OOM

重點:堆記憶體分代結構

┌─────────────────────────────────────┐
│              Heap                   │
├──────────────┬──────────────────────┤
│  Young Gen   │      Old Gen         │
│  (新生代)    │      (老年代)        │
│ ┌──────┐ ┌──┐│                      │
│ │ Eden │ │S0││  長期存活物件        │
│ └──────┘ │  ││  (大物件、長壽命)    │
│          │S1││                      │
│          └──┘│                      │
└──────────────┴──────────────────────┘
  • Eden 區:新物件誕生地,大多數物件朝生夕死。
  • Survivor 區 (S0/S1):經過一次 Minor GC 仍存活的物件進入,雙區輪換複製。
  • 老年代:經過多次 GC 仍存活(預設年齡 ≥ 15)或大物件直接進入。

方法區演進

  • JDK 7:永久代,固定大小,易 OOM。
  • JDK 8:元空間,使用本地記憶體,預設無上限(受物理記憶體限制)。
  • 類元資料、常量池、靜態變數移至元空間;字串常量池、靜態變數實例移至堆。

垃圾回收核心演算法

對象存活判定

  1. 引用計數法:簡單但無法解決循環引用,JVM 未採用。
  2. 可達性分析法(標準):
    • GC Roots:棧幀局部變數、方法區靜態屬性/常量、JNI 引用、同步鎖持有物件等。
    • 從 GC Roots 向下搜索,不可達物件標記為可回收。
    • 需經過兩次標記(第一次標記、第二次篩選 finalize())才真正回收。

四大基礎演算法

新生代:複製演算法優化

  • 實際劃分:Eden : S0 : S1 = 8 : 1 : 1(可調 -XX:SurvivorRatio)。
  • 每次使用 Eden + 一個 Survivor,GC 時存活者複製到另一 Survivor,清空 Eden 和用過的 Survivor。
  • 大物件(-XX:PretenureSizeThreshold)或長壽命物件(-XX:MaxTenuringThreshold)直接進老年代。

老年代:標記-整理/標記-清除

  • Parallel Old:標記-整理,多線程並行。
  • CMS:標記-清除,併發低停頓,但產生碎片。
  • G1:區域化分代,混合收集,可預測停頓。
  • ZGC/Shenandoah:併發整理,超低停頓(< 10ms)。

常用 GC 收集器對比

演算法核心思想優點缺點適用區域
標記-清除標記存活,清除其餘實現簡單記憶體碎片化、效率低老年代
複製劃分兩塊,存活者複製無碎片、分配快記憶體利用率 50%新生代
標記-整理標記後向一端移動無碎片、利用率高移動開銷大老年代
分代收集依壽命分區,異策略綜合優勢、高效實現複雜全堆
收集器模式新生代/老年代演算法特點適用場景
Serial串行新/老複製/標記-整理單線程、暫停所有應用線程Client 模式、小應用
Parallel Scavenge並行新生代複製高吞吐量、自適應調優批次處理、科學計算
Parallel Old並行老年代標記-整理多線程、高吞吐搭配 Parallel Scavenge
CMS併發老年代標記-清除低停頓、併發收集、碎片化Web 服務、響應敏感
G1混合全堆標記-整理+複製區域化、可預測停頓、大堆友好大記憶體、多核、JDK 9+ 預設
ZGC併發全堆併發整理亞毫秒停頓、TB 級堆超大堆、極低延遲需求

開發者優化指南

減少 GC 壓力

  1. 避免顯式 System.gc():觸發 Full GC,影響效能。
  2. 減少臨時物件:複用物件、使用物件池、基本型別替代包裝類。
  3. 字串拼接用 StringBuilder:避免大量 String 臨時物件。
  4. 及時釋放引用:作用域結束賦 null、集合用完 clear()。
  5. 謹慎使用靜態集合:生命週期長,易造成記憶體洩漏。

JVM 參數調優關鍵

-Xms512m -Xmx512m              # 堆固定大小,避免震盪
-Xmn256m                        # 新生代大小
-XX:SurvivorRatio=8             # Eden:Survivor 比例
-XX:MaxTenuringThreshold=15     # 晉升老年代年齡
-XX:+UseG1GC                    # 啟用 G1
-XX:MaxGCPauseMillis=200        # 目標停頓時間
-XX:+HeapDumpOnOutOfMemoryError # OOM 時導出堆快照
-XX:HeapDumpPath=/logs/heap.hprof

排查工具鏈

  • jstat / jmap / jhat:命令列監控與堆分析。
  • VisualVM / JConsole:圖形化監控、堆 Dump 分析。
  • Arthas / Async Profiler:線上診斷、火焰圖。
  • MAT (Memory Analyzer Tool):深度堆分析、洩漏追蹤。

總結

理解 JVM 記憶體模型與 GC 機制,是解決 OOM、長停頓、記憶體洩漏等生產疑難雜症的前提。掌握分代假設、收集器特性、調優參數與工具鏈,能讓 Java 應用在高併發、大數據、低延遲場景下穩定高效運行。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved