Java 虛擬機採用基於棧的架構,指令流由單字節操作碼(0~255)與後續操作數組成。理解字節碼指令,是掌握 JVM 執行原理、編譯優化、動態代理、字節碼操作框架(ASM、ByteBuddy)以及逆向分析的核心技能。本文系統梳理指令分類、操作數棧交互模式、類型相關指令設計哲學及常用指令速查表。
(byte1 << 8) | byte2)。| 策略 | 優勢 | 劣勢 |
|---|---|---|
| 放棄對齊 | 緊湊編碼,減少填充字節,提高網絡傳輸/存儲效率(Java 初衷面向網絡/嵌入式) | 解釋執行時需額外解碼組裝數據結構,損失部分 CPU 性能 |
| 指令 | 含義 | 指令 | 含義 |
|---|---|---|---|
iload / iload_<n> | 第 n 個 int 型局部變量入棧 | istore / istore_<n> | 棧頂 int 存入第 n 個局部變量 |
lload / lload_<n> | long 型(佔 2 slot) | lstore / lstore_<n> | 棧頂 long 存入 |
fload / fload_<n> | float 型 | fstore / fstore_<n> | 棧頂 float 存入 |
dload / dload_<n> | double 型(佔 2 slot) | dstore / dstore_<n> | 棧頂 double 存入 |
aload / aload_<n> | 引用型 | astore / astore_<n> | 棧頂引用存入 |
_<n>(n=0~3)為隱式索引優化指令,字節碼更短、執行更快。
| 指令 | 含義 |
|---|---|
aconst_null | null 入棧 |
iconst_m1 ~ iconst_5 | int -1 ~ 5 入棧(高頻常量專用指令) |
lconst_0 / fconst_0 / dconst_0 | long/float/double 0 入棧 |
bipush / sipush | byte/short 常量入棧(帶操作數) |
ldc / ldc_w / ldc2_w | 從常量池加載 int/float/String / long/double(_w 寬索引) |
| 指令 | 含義 |
|---|---|
pop / pop2 | 棧頂 1/2 slot 出棧 |
dup | 復制棧頂 1 slot,壓入棧頂 |
dup_x1 / dup_x2 | 復制棧頂 1 slot,插入第 2/3 位置 |
dup2 / dup2_x1 / dup2_x2 | 復制棧頂 2 slot(long/double 視為 1 slot) |
swap | 交換棧頂兩個 1 slot 值(不適用 long/double) |
關鍵點:
dup2的「2」指 2 個 slot。long/double 佔 2 slot 但視為 1 個邏輯值,dup2只復制一個 long/double。
| 指令 | 含義 |
|---|---|
getstatic / putstatic | 靜態字段讀/寫 |
getfield / putfield | 實例字段讀/寫 |
| 指令 | 用途 | 分派邏輯 |
|---|---|---|
invokevirtual | 實例方法 | 虛方法分派(多態) |
invokestatic | 靜態方法 | 靜態綁定 |
invokeinterface | 接口方法 | 運行時搜索實現類 |
invokespecial | 特殊實例方法 | <init>、父類方法、private 方法 |
invokedynamic | 動態語言支持 | 用戶引導方法動態解析 |
| 指令 | 返回類型 |
|---|---|
ireturn / lreturn / freturn / dreturn / areturn / return | int/long/float/double/ref/void |
new、newarray(基本類型)、anewarray(引用類型)、multianewarray(多維)。xaload / xastore(x = b/c/s/i/l/f/d/a)。arraylength。instanceof、checkcast。僅支持整型、浮點型。iadd/ladd/fadd/dadd、isub/...、imul/...、idiv/...、irem/...、ineg/...。
其他:位移(ishl/ishr/iushr)、位運算(ior/iand/ixor)、自增(iinc)、比較(lcmp、fcmpg/fcmpl、dcmpg/dcmpl)。
i2b/i2c/f2i/d2l 等)。規範規定窄化永不拋出異常,溢出按截斷處理,NaN 轉 int/long 為 0。ifeq/ifne/iflt/ifge/ifgt/ifle(int 比較 0)、if_icmpeq/...(int 比較)、ifnull/ifnonnull、if_acmpeq/if_acmpne(引用比較)。tableswitch(連續 case)、lookupswitch(稀疏 case)。goto/goto_w、jsr/jsr_w/ret(歷史遺留,finally 實現)。athrow。捕獲由異常表實現,非指令。monitorenter(進入管程)、monitorexit(退出管程)。編譯器自動生成異常處理器保證成對調用(正常/異常退出均執行 exit)。除 load(局部變量→棧)、store(棧→局部變量)外,絕大多數指令只操作操作數棧:取操作數、計算、放結果。這正是「基於棧架構」的本質體現——局部變量表僅作為變量存儲,運算邏輯完全在棧上流轉。
# 反編譯類文件查看字節碼
javap -c -v MyClass.class
# 關鍵參數
-c # 反編譯方法體字節碼
-v # 詳細輸出(常量池、行號表、局部變量表、Code 屬性等)
-p # 顯示私有成員
-sysinfo # 顯示系統信息
結合 javap 輸出與本文指令表,可逐行還原 Java 源碼的編譯邏輯,是分析編譯器優化、動態代理生成代碼、框架字節碼增強的利器。