1. 程式人生 > >JVM總結(二)

JVM總結(二)

JVM總結(2)java記憶體區域、位元組碼執行引擎

1、記憶體區域

程式計數器:知道執行緒執行位置,保證執行緒切換後能恢復到正確的執行位置。

虛擬機器棧:存棧幀。棧幀裡存區域性變量表、操作棧、動態連線、方法返回地址。區域性變量表又存了各種基本資料型別和物件引用(控制代碼)。

本地方法棧:為Native方法服務

堆:存放物件例項和陣列,可以處於物理上不連續的記憶體空間

方法區:存類資訊、常量、靜態變數。有執行時常量池,存放類的符號引用

堆主要用來存放物件,棧主要用來執行程式。

2、物件的建立

虛擬機器遇到一條new指令時,會先去常量池檢測能否找到new對應的類的符號引用,並檢測這個類是否載入、初始化。

如果載入檢查通過,則分配記憶體。分配記憶體有兩種方式:⑴指標碰撞,針對連續記憶體區域;⑵空閒列表,針對不連續記憶體區域。

記憶體分配完之後,會對記憶體初始化零值,保證例項欄位能在java程式碼不賦初值也能使用。

接下來對物件資訊進行設定,把類的元資料資訊、物件的雜湊碼、物件的GC分代年齡等資訊存放在物件頭之中。

最後執行使用者的Init方法

 

3、物件的記憶體佈局

分為三部分,物件頭、例項資料、對齊填充

物件頭:⑴物件自身執行時資料,如雜湊碼、GC分代年齡、鎖狀態標誌、執行緒持有的鎖等。⑵型別指標,虛擬機器通過這個來確定這個物件是哪個類的例項。⑶如果物件是一個Java陣列,那麼物件頭中還必須有一塊用於記錄陣列長度的資料。

例項資料:物件真正儲存的有效資訊,也是在程式程式碼中定義的各種型別的欄位內容。

對齊填充:JVM要求物件的起始地址必須是8位元組的整數倍,因此當物件例項資料沒有對齊時,這部分來補全。

物件的訪問定位

取決於虛擬機器的實現而定,有“控制代碼”和“直接指標”兩種方式

“控制代碼”的好處是,在物件被移動(垃圾回收時很普遍),只用修改控制代碼中的例項資料指標,而reference本身不用修改。

“直接指標”的好處是,速度更快,畢竟節省了一次指標定位的時間開銷。由於物件的訪問在Java中非常頻繁,因此這部分開銷節省下來也很可觀。

JVM位元組碼執行引擎


位元組碼檔案即類檔案被載入後,就能送入執行引擎了:

輸入:位元組碼檔案

處理:位元組碼解析

輸出:執行結果。

物理機的執行引擎是由硬體實現的,虛擬機器的執行引擎由於自己實現的。

• 棧幀(Stack Frame)是用於支援虛擬機器進行方法呼叫和方法執行的資料結構,它是虛擬機器執行時資料區中的虛擬機器棧(Virtual Machine Stack)的棧元素。

• 每個棧幀都包括了一下幾部分:區域性變量表、運算元棧、動態連線、方法的返回地址 和一些額外的附加資訊。

• 每一個方法從呼叫開始至執行完成的過程,都對應著一個棧幀在虛擬機器棧裡面從入棧到出棧的過程。

• 一個棧幀需要分配多少記憶體,不會受到程式執行期變數資料的影響,而僅僅取決於具體的虛擬機器實現。在活動執行緒中,只有位於棧頂的棧幀才是有效的,稱為當前棧幀,與這個棧幀相關聯的方法稱為當前方法,執行引擎執行的所有位元組碼指令都只針對當前棧幀進行操作。

區域性變量表:

一組變數值儲存空間,用於存放方法引數和方法內部定義的區域性變數。以變數槽slot為單位,一個slot可以放32位資料型別,對於long\double佔用2個slot。

 

運算元棧:

即用來存放運算元的棧結構,當一個方法剛開始執行的時候,這個方法的運算元棧是空的,在方法的執行過程中,會有各種位元組碼指令向運算元棧中寫入和提取內容,也就是入棧和出棧的操作。

java虛擬機器的解釋執行引擎稱為基於棧的執行引擎,其中所指的棧就是運算元棧。

動態連線:

執行期將相關的符號引用轉換為直接引用

方法返回地址:

方法執行完成的結果值

方法呼叫:

解析方法的符號引用和確定方法的版本

方法的執行:

解釋執行(通過直譯器執行)

編譯執行(通過JIT編譯器產生原生代碼執行)

基於棧的程式碼執行示例

下面我們用簡單的案例來解釋一下JVM程式碼執行的過程,程式碼例項如下:

使用javap指令檢視位元組碼: