標籤:
英文原文連結,譯文連結,原文James Bloom,譯者:有孚
明白Java代碼是如何編譯成位元組碼並在JVM上啟動並執行非常重要,這有助於理解程式啟動並執行時候究竟發生了些什麼。理解這點不僅能搞清語言特性是如何?的,並且在做方案討論的時候能清楚相應的副作用及權衡利弊。
本文介紹了Java代碼是如何編譯成位元組碼並在JVM上執行的。想瞭解JVM的內部結構以及位元組碼運行時用到的各個記憶體地區,可以看下我前面的一篇關於JVM內部細節的文章。
本文分為三部分,每一部分都分成幾個小節。每個小節都可以單獨閱讀,不過由於一些概念是逐步建立起來的,如果你依次閱讀完所有章節會更簡單一些。每一節都會覆蓋到Java代碼中的不同結構,並詳細介紹了它們是如何編譯並執行的。
1. 第一部分, 基礎概念
變數局部變數
JVM是一個基於棧的架構。方法執行的時候(包括main方法),在棧上會分配一個新的幀,這個棧幀包含一組局部變數。這組局部變數包含了方法運行過程中用到的所有變數,包括this引用,所有的方法參數,以及其它局部定義的變數。對於類方法(也就是static方法)來說,方法參數是從第0個位置開始的,而對於執行個體方法來說,第0個位置上的變數是this指標。
局部變數可以是以下這些類型:
* char
* long
* short
* int
* float
* double
* 引用
* 返回地址
除了long和double類型外,每個變數都只佔局部變數區中的一個變數槽(slot),而long及double會佔用兩個連續的變數槽,因為這些類型是64位的。
當一個新的變數建立的時候,運算元棧(operand stack)會用來儲存這個新變數的值。然後這個變數會儲存到局部變數區中對應的位置上。如果這個變數不是基礎類型的話,本地變數槽上存的就只是一個引用。這個引用指向堆的裡一個對象。
比如:
int i = 5;
編譯後就成了
0: bipush 52: istore_0
| bipush |
用來將一個位元組作為整型數字壓入運算元棧中,在這裡5就會被壓入運算元棧上。 |
| istore_0 |
這是istore_這組指令集(譯註:嚴格來說,這個應該叫做作業碼,opcode ,指令是指作業碼加上對應的運算元,oprand。 不過作業碼一般作為指令的助記符,這裡統稱為指令)中的一條,這組指令是將一個整型數字儲存到本地變數中。 n代表的是局部變數區中的位置,並且只能是0,1,2,3。再多的話只能用另一條指令istore了,這條指令會接受一個運算元,對應的是局部變數區中的位置資訊。 |
Java位元組碼淺析(—)