bilibili-JVM學習筆記16
The Java Virtual Machine Specification - Java SE 8 Edition
JVM學習筆記11 - Java字節碼初識
JVM學習筆記12 - 解讀筆記11中的attributes
JVM學習筆記13
JVM學習筆記14 異常
JVM學習筆記15 方法執行
編譯執行 解釋執行
- 現代 JVM 在執行 Java 代碼的時候,通常都會將解釋執行與編譯執行二者結合起來進行;
解釋執行
- 通過 jvm 解釋器來讀取字節碼,遇到相應的字節碼指令就去執行該指令;
編譯執行
- 通過
即時編譯器
(Just In Time,JIT
)將字節碼指令轉換爲本地機器碼
來執行;現代 JVM 會根據代碼熱點
來生成相應的本地機器碼; - 失去了可移植性的優點
- 提高了執行效率
- 通過
- 基於棧的指令集與基於寄存器的指令集之間的關係
- JVM 執行字節碼指令所採取的方式是基於棧的指令集
- 主要操作有入棧和出棧;
- 優點:可以在不同平臺之間移植
- 缺點:完成相同的操作,指令數量通常比基於寄存器的指令集數量要多;在內存中完成執行指令的操作,速度慢很多;
- 雖然虛擬機可以採用一些優化手段,但總體來說,基於棧的指令集的執行還是要慢一些的;
- 基於
寄存器
的指令集- 與硬件架構緊密關聯,無法做到可移植;
- 基於寄存器的指令集是直接由
CPU
來執行的,它是在高速緩衝區
中進行執行的,速度比在內存中執行高出一個數量級;
- JVM 執行字節碼指令所採取的方式是基於棧的指令集
JVM執行棧指令集實例剖析
java 源碼
package new_package.jvm.p55;
public class MyTest {
public int cal() {
int a = 6;
int b = 1;
int c = 5;
int d = 3;
int result = (a + b - c) * d;
return result;
}
public static void main(String[] args) {
System.out.println(new MyTest().cal());
}
}
javap -v new_package.jvm.p55.MyTest
cal 方法
相關的字節碼
public int cal();
descriptor: ()I
flags: ACC_PUBLIC
Code:
stack=2, locals=6, args_size=1
0: bipush 6
2: istore_1
3: iconst_1
4: istore_2
5: iconst_5
6: istore_3
7: iconst_3
8: istore 4
10: iload_1
11: iload_2
12: iadd
13: iload_3
14: isub
15: iload 4
17: imul
18: istore 5
20: iload 5
22: ireturn
LineNumberTable:
line 6: 0
line 7: 3
line 8: 5
line 9: 7
line 10: 10
line 11: 20
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 this Lnew_package/jvm/p55/MyTest;
3 20 1 a I
5 18 2 b I
7 16 3 c I
10 13 4 d I
20 3 5 result I
解析:
- stack=2 表示當前方法的
操作數棧
最大深度爲 2 - locals=6 表示當前方法
局部變量表
長度爲 6 - args_size=1 表示當前方法入參數量爲 1 ;(
實例方法
的第一個隱形入參this
,指向當前實例)
接下來對字節碼指令逐個解釋:
- bipush 6
bipush :將一個 int 類型的數值壓入操作數棧
此處是將數值 6
壓入操作數棧
2. istore_1
istore_1 : istore 1 的簡寫;
將操作數棧頂的 int 類型數值從操作數棧中彈出,放到局部變量表的索引爲 1
的位置處
iconst_1 : bipush 1 的簡寫
此處是將數值 1
壓入操作數棧
- istore_2
將操作數棧頂的 int 類型數值從操作數棧中彈出,放到局部變量表的索引爲 2
的位置處
- iconst_5
此處是將數值 5
壓入操作數棧
- istore_3
將操作數棧頂的 int 類型數值從操作數棧中彈出,放到局部變量表的索引爲 3
的位置處
- iconst_3
此處是將數值 3
壓入操作數棧
- istore 4
將操作數棧頂的 int 類型數值從操作數棧中彈出,放到局部變量表的索引爲 4
的位置處
iload_1 : iload 1 的簡寫
iload 從局部變量中加載一個 int 類型的值
iload_1 即從索引 1 的位置加載一個值,壓入操作數棧
- iload_2
iload_2 即從索引 2 的位置加載一個值,壓入操作數棧
從操作數棧中彈出兩個值(int 類型的值),然後相加,將結果壓入操作數棧
- iload_3
從索引 3 的位置加載一個值,壓入操作數棧
從操作數棧中彈出兩個數(int 類型),第一個爲減數,第二個爲被減數,結果爲被減數 - 減數,將結果重新壓入操作數棧;
- iload 4
從索引 4 的位置加載一個值,壓入操作數棧
兩個 int 類型的值相乘,並將結果重新壓入操作數棧;
- istore 5
將操作數棧頂的 int 類型數值從操作數棧中彈出,放到局部變量表的索引爲 5
的位置處
- iload 5
從索引 5 的位置加載一個值,壓入操作數棧
從當前幀的操作數棧中彈出值,並將其壓入調用者的幀
的操作數棧
。