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

Java 虛擬機架構深度解析:類加載、運行時數據區、執行引擎全景圖

     編輯:Java 相關知識

JVM 三重含義

  • 規範:The Java Virtual Machine Specification,定義指令集、類文件格式、驗證規則等。
  • 實現:HotSpot、OpenJ9、GraalVM、Zing 等具體代碼實現。
  • 實例:運行中的 Java 進程,每個 java -jar app.jar 啟動一個 JVM 實例。

JVM 生命周期

啟動

  • Bootstrap ClassLoader 加載初始類(含 public static void main(String[]))。
  • 執行 main 方法,啟動主線程(非守護線程)。

退出

  • 所有非守護線程結束 → JVM 退出。
  • 調用 System.exit() / Runtime.getRuntime().halt() → 強制退出。
  • 收到 SIGTERM/SIGINT(Ctrl+C)→ 觸發 Shutdown Hook 後退出。

守護線程:GC、JIT 編譯線程等;thread.setDaemon(true) 必須在 start() 前調用。

JVM 系統架構圖

JVM 架構圖

核心子系統詳細解析

1. 類加載子系統

職責

加載 .class 文件 → 驗證 → 準備 → 解析 → 初始化 → 可用。核心接口 ClassLoader。

雙親委派模型

Bootstrap ClassLoader (C++ 實現)
    ↑ 加載核心庫 (rt.jar/jrt-fs.jar)
Platform ClassLoader (Java 9+)
    ↑ 加載擴展/平台模塊
Application ClassLoader (AppClassLoader)
    ↑ 加載類路徑 (-cp) 應用類
Custom ClassLoader (用戶自定義)
    ↑ 隔離插件、熱部署、加密類等
  • 子類加載器優先委派父類加載,避免核心類被篡改、重複加載。
  • 打破雙親委派:Tomcat (WebappClassLoader 先自加載)、OSGi、JDBC SPI (Thread.contextClassLoader)。

2. 運行時數據區

區域線程共享?生命周期核心內容OOM 風險
堆✅ 所有線程共享JVM 啟動~關閉對象實例、數組、字符串常量池 (JDK 7+)高:-Xmx 限制
方法區✅ 共享JVM 啟動~關閉類元數據、常量池、靜態變量、即時編譯代碼緩存中:-XX:MaxMetaspaceSize
Java 虛擬機棧❌ 線程私有線程創建~結束棧幀:局部變量表、操作數棧、動態連接、方法返回地址中:-Xss 限制
本地方法棧❌ 線程私有線程創建~結束Native 方法調用狀態 (JNI)低
程序計數器❌ 線程私有線程創建~結束當前執行字節碼指令地址無(極小)

堆內存結構 (HotSpot, 分代假說)

Heap
├── Young Generation (新生代)
│   ├── Eden Space (伊甸區)          -- 新對象分配主區
│   ├── Survivor Space S0 (From)     -- Minor GC 存活對象
│   └── Survivor Space S1 (To)       -- 輪換
└── Old Generation (老年代)           -- 長期存活對象晋升
    (JDK 8-) PermGen (永久代) → (JDK 8+) Metaspace (元空間, 直接內存)

棧幀結構

  • 局部變量表:this、方法參數、局部變量(Slot,32位),long/double 佔 2 Slot。
  • 操作數棧:字節碼指令操作數入棧/出棧,如 iadd 彈出兩個 int 相加壓入結果。
  • 動態連接:指向運行時常量池中該方法引用,支持動態調用。
  • 方法返回地址:正常返回或異常返回的下一條指令位置。

3. 執行引擎

解釋器 vs 即時編譯器 (JIT)

  • 解釋器:逐條解釋執行字節碼,啟動快、執行慢。
  • JIT 編譯器:熱點代碼 (高頻調用/循環) 編譯為本地機器碼,執行快、編譯耗時。
  • 分層編譯 (JDK 7+):C1 (Client Compiler) 快速編譯 → C2 (Server Compiler) 深度優化,平衡啟動與峰值性能。

垃圾收集器 (GC) 核心

4. 本地庫接口 (JNI)

  • Java 調用 C/C++ 庫:native 方法聲明 → javac -h 生成頭文件 → 實現 .c/.cpp → 編譯為 .so/.dll → System.loadLibrary。
  • 性能開銷:JNI 調用邊界檢查、數據複製、GC 掃描本地引用,高頻調用需謹慎。

HotSpot 對象內存佈局 (64位壓縮指針開啟)

收集器代算法特點適用場景
Serial新/老複製/標記整理單線程、Client 模式默認單核、小內存
Parallel Scavenge新複製多線程、吞吐量優先批處理、科學計算
CMS老標記清除並發標記、低停頓、碎片化響應敏感應用 (JDK 14 移除)
G1混合標記整理+區域化可預測停頓、Region 分區、大對象 HumongousJDK 9+ 默認、大堆 (6G+)
ZGC / Shenandoah混合並發整理、着色指針/轉發指針亞毫秒停頓、TB 級堆超大堆、極低延遲要求
區域大小說明
對象頭16 BytesMark Word (12B) + Klass Pointer (4B, 壓縮)
實例數據實例變量大小按聲明順序/分配策略排列,對齊補齊 8 Bytes
對齊填充0~7 Bytes確保對象起始地址 8 Bytes 對齊

Mark Word 狀態變遷 (64位)

| 無鎖 (25b Hash | 4b Age | 2b 0 | 1b 01) |
| 偏向鎖 (23b ThreadID | 2b Epoch | 4b Age | 1b 1 | 1b 01) |
| 輕量級鎖 (62b 指向棧中 Lock Record | 2b 00) |
| 重量級鎖 (62b 指向 ObjectMonitor | 2b 10) |
| GC 標記 (62b 空 | 2b 11) |
  • 偏向鎖:無競爭時消除 CAS,線程 ID 寫入 Mark Word,後續進入同步塊無同步開銷。
  • 輕量級鎖:CAS 將 Mark Word 替換為棧中 Lock Record 指針,適合輕度競爭。
  • 重量級鎖:膨脹為 ObjectMonitor,依賴 OS 互斥量,線程阻塞/喚醒涉及用戶態↔內核態切換。

常用調優參數速查

-Xms4g -Xmx4g                 # 堆固定 4G,避免動態伸縮
-XX:+UseG1GC                  # 啟用 G1
-XX:MaxGCPauseMillis=200      # 目標停頓 200ms
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/heap.hprof
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m
-Xss1m                        # 棧大小 1M (默認 1M, 深遞歸可調大)
-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xlog:gc*:/logs/gc.log (JDK 9+)

總結

JVM 是 Java「一次編寫,到處運行」的基石。理解類加載雙親委派、運行時數據區分代模型、JIT 分層編譯、GC 演進脈絡、鎖升級機制五大核心,能從根本上定位內存洩漏、CPU 飆高、停頓抖動等生產疑難雜症。建議開發者熟練使用 jstat、jmap、jstack、arthas、JMC/JFR 等診斷工具,建立「觀測 → 分析 → 調優」閉環能力。

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