每當啓動一個新線程時,Java虛擬機都會爲它分配一個Java棧。Java棧以幀爲單位保存線程的運行狀態。虛擬機只會直接對Java棧執行兩個操作:以幀爲單位的壓棧或出棧。當線程調用一個Java方法時,虛擬機都會在該線程的Java棧中壓入一個新棧。
棧幀:
棧幀由三部分組成:局部變量,操作數棧和棧數據區。
當虛擬機調用一個Java方法時,它從對應類的信息中得到此方法的局部變量和操作數據棧的大小,並據此分配棧幀內存,然後壓入Java棧中。
1)局部變量:Java棧幀的局部變量區被組織爲一個以字節爲單位,從0開始計數的數組。
2)操作數棧:和局部變量一樣,被組織成一個字長爲單位的數組。通過標準的棧操作——壓棧和出棧來訪問。
3)棧數據區:Java棧中支持常量池解析,正常方法返回以及異常派發機制的一些信息。
例子:
一個斐波那契序列的代碼,如下:
class Fibonacci {
static void calcSequence() {
long fiboNum = 1;
long a = 1;
long b = 1;
for (;;) {
fiboNum = a + b;
a = b;
b = fiboNum;
}
}
}
指令碼: 0 lconst_1 // Push long constant 1
1 lstore_0 // Pop long into local vars 0 & 1: long a = 1;
2 lconst_1 // Push long constant 1
3 lstore_2 // Pop long into local vars 2 & 3: long b = 1;
4 lconst_1 // Push long constant 1
5 lstore 4 // Pop long into local vars 4 & 5: long fiboNum = 1;
7 lload_0 // Push long from local vars 0 & 1
8 lload_2 // Push long from local vars 2 & 3
9 ladd // Pop two longs, add them, push result
10 lstore 4 // Pop long into local vars 4 & 5: fiboNum = a + b;
12 lload_2 // Push long from local vars 2 & 3
13 lstore_0 // Pop long into local vars 0 & 1: a = b;
14 lload 4 // Push long from local vars 4 & 5
16 lstore_2 // Pop long into local vars 2 & 3: b = fiboNum;
17 goto 7 // Jump back to offset 7: for (;;) {}
虛擬機鏡像:
1)初始化。Local Variables:局部變量。Operand Stack:操作數棧。
2)分配3個變量:fiboNum,a,b。局部變量是一個3位的數組。
3)lload_0:從局部變量0中裝載long類型值,lload_2:從局部變量2中裝載long類型值。
4)ladd:執行int類型的加法。
5)istore 4:從棧中彈出int類型值,然後將其存到位置爲4的局部變量中。
參考資料:
《深入Java虛擬機》