JVM 整體架構
Java源碼 → 編譯器 → 字節碼(*.class) → 類加載器 → 方法區/堆/棧 → 執行引擎
類加載器雙親委派模型
- 啟動類加載器: C++ 實現,加載核心庫(
rt.jar),無父加載器。
- 擴展/應用類加載器: Java 實現,遞歸委派父加載器,失敗再自行加載。
- 命名空間隔離: 每個加載器維護獨立命名空間,相同全限定名類若由不同加載器加載則不相等(
ClassA != ClassB)。
運行時數據區
| 區域 | 線程共享 | 核心內容 |
| 方法區 | 是 | 類元數據、常量池、靜態變量、方法字節碼、方法表(非抽象類) |
| 堆 | 是 | 所有對象實例、數組、實例變量 |
| Java 虛擬機棧 | 否 | 棧幀:局部變量表、操作數棧、幀數據區(異常表、常量池解析引用) |
| 本地方法棧 | 否 | Native 方法調用狀態(C 棧等) |
| 程序計數器 | 否 | 當前執行字節碼指令地址 |
對象佈局與訪問
- 對象頭:Mark Word(哈希碼、GC 年齡、鎖狀態)、類元數據指針、數組長度(若為數組)。
- 實例數據:字段值(含繼承字段)。
- 對齊填充:8 字節對齊。
- 訪問方式:句柄池 vs 直接指針(HotSpot 採用直接指針)。
常量池與動態連接
- 靜態常量池:Class 文件中,存字面量、符號引用(類/接口/字段/方法全限定名+描述符)。
- 運行時常量池:方法區中,類加載時從靜態常量池創建,解析階段將符號引用替換為直接引用(指針/偏移量),實現動態連接。
String.intern() 運行時常量池去重。
執行引擎與字節碼指令
- 基於棧的指令集:操作數棧作為工作區,
iload/istore 讀寫局部變量表,iadd 等運算指令彈棧壓棧。
- 強類型轉換:低精度→高精度隱式,高→低需顯式指令(
i2l、l2d 等)。
- 方法調用指令:
invokestatic/invokespecial/invokevirtual/invokeinterface/invokedynamic。
線程與同步原語
- 線程 = 進程內執行體,擁有獨立 PC、棧,共享堆/方法區。
- 監視器鎖:
monitorenter/monitorexit 字節碼實現 synchronized,支持重入(計數器)。
Object.wait/notify/notifyAll 配合鎖實現等待/通知模式,wait 釋放鎖進入等待集。
異常處理機制
方法區異常表記錄 try 範圍(起始/結束 PC)、異常類型、處理器 PC。拋出異常時搜尋當前幀異常表,匹配則跳轉處理器;否則彈出幀向上傳遞。
經典面試題:String 對象創建與比較
String a = new String("hello"); // 堆新建對象
String b = new String("hello"); // 堆另一對象
String c = "hello"; // 常量池字面量
String d = "hello"; // 同一常量池引用
a == b → false; c == d → true;
== 比較引用地址,equals() 比較內容。
- 上一篇文章: Swing 自定義日曆控件開發實戰
- 下一篇文章: J2EE 十三大核心技術全景解析與 WebLogic 實戰應用
Copyright ©
程式碼之家 All Rights Reserved