前言
java虛擬機是java跨平台的基石,本文的描述以jdk7.0為准,其他版本可能會有一些微調。
引用
棧幀
- 每當一個java方法被執行時都會在虛擬機中新創建一個棧幀,方法調用結束后即被銷毀。
- 棧幀存儲空間為虛擬機棧,每一個棧幀都有自己的局部變量表、操作數棧和指向當前方法所屬的類的運行時常量池的引用。
- 在每個線程中,只有目前正在執行的那個方法的棧幀是活動的。這個棧幀就稱為當前棧幀(current frame),這個棧幀對應的方法稱之為當前方法(current method)。定義這個方法的類就稱之為當前類(current class)。對局部變量表和操作數棧的各種操作,通常都指的是對當前棧幀的局部變量表和操作數棧進行的操作。如下圖所示,
變量
局部變量
- 每一個棧幀包含一組局部變量,這組局部變量中包含了方法運行時所需要的所有的變量(含this引用)、方法參數和其他定義的局部變量。局部變量的類型包括以下幾種:
- boolean
- byte
- char
- short
- int
- float
- reference
- returnAddress
- long
- double
- 除了long和double外,其他所有的變量在局部變量表中都只占一個槽位(slot),而long和double占2個槽位。
- 特別值得一提的是,當一個實例方法被調用的時候,局部變量表中的第0個局部變量一定是用來存儲被調用的實例方法所在的對象引用。(this關鍵字,可以參考下面示例中的字節碼截圖),后續的其他參數將會傳遞至從1開始的局部變量表位置上。
- 示例:
- 以下圖中的代碼為例:
- 對應的字節碼如下:
- 具體的操作流程示意:
- 釋義:
- 從上圖中我們可以看出例如
int x=12
,在jvm中對應着兩個指令bipush 10
,bipush指令用於將一個byte作為一個整型數字插入到操作數棧中(oprand stack),這里將10插入到操作數棧istore_1
,istore_1指令(實際上這個應該稱之為操作碼opcode,指令是指操作碼加上操作數oprand)是istore_指令組中的一個,用於將一個整型數字存儲到局部變量中, <n>
代表的是局部變量表中的存儲位置,同時只能為0,1,2,3;超過3了就只能使用istore指令。
- 注意,
istore_1
操作碼和istore 4
指令兩者的區別為- 前者只是一個操作碼,只占一個單位的長度,后者是操作碼和操作數組合的指令,占2個單位的長度。(注意看Code中每一行指令前面的數字)
- 從上圖中我們可以看出例如
- 思考:
- 看了上圖的字節碼中可能有人會問,為什么還需要istore和iload這兩個指令呢?這是因為棧本身不是用來存儲數據的,而是用局部變量表來存儲。局部變量通過索引尋址。