每當啟動一個新線程時,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 result10 lstore 4 // Pop long into local vars 4 & 5: fiboNum = a + b;12 lload_2 // Push long from local vars 2 & 313 lstore_0 // Pop long into local vars 0 & 1: a = b;14 lload 4 // Push long from local vars 4 & 516 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虛擬機器》