JVM總結(二) 阿新 • • 發佈:2019-08-11 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指令檢視位元組碼: