深入Java虛擬機-讀書筆記一Java運行時數據區域和對象創建和訪問

深入Java虛擬機-讀書筆記一Java運行時數據區域和對象創建和訪問

Java運行時數據區域

Java虛擬機在執行程序時把它所管理的內存劃分爲若干不同的數據區域。這些區域都有各自的用戶,以及創建和銷燬的時間。如下圖
這裏寫圖片描述

程序計數器

一塊較小的內存空間,可以看作是當前線程所執行的字節碼的行號指示器。由於Java虛擬機的多線程是通過線程輪流切換並分配處理器執行時間的方式來實現,在任何一個確定的時刻,一個處理器都只會執行一條線程中的指令。因此,爲了線程切換後能恢復到正確的執行位置,每條線程都需要一個獨立的計數器,因此屬於線程私有的內存。
如果線程正在執行一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址,如果正在執行的是Native方法,這個計數器的值爲空。

Java虛擬機棧

也是線程私有的,生命週期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法執行的同時都會創建一個棧幀用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息。每個方法從調用值至執行完成的過程,就對應着一個棧幀在虛擬機中入棧和出棧的過程。

本地方法棧

和Java虛擬機棧作用相似,爲虛擬機使用的Native方法服務

Java堆

堆是所有線程共享的一塊內存區域。存放幾乎所有對象的實例。幾乎所有的對象實例以及數組都在堆上分配。

方法區

各個線程共享的內存區域,用於存儲以及被虛擬機加載的類信息,常量,靜態變量,及時編譯器編譯後的代碼等數據。

運行時常量池

是方法區的一部分。Class文件中除了類的信息外,還有一項信息是常量池,用於存放編譯期生成的各種字面量和符號引用,這部分內容將在類加載後進入方法區的運行時常量池中存放

對象的創建

虛擬機遇到一條new指令時,首先會檢查這個指令的參數是否能在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已被加載,解析,和初始化過。如果沒有,則先執行類的加載過程。
類加載完成後,爲對象在Java堆中分配一塊內存。內存分配完成後,虛擬機需要將分配到的內存空間都初始化爲零值。這步操作保證了對象的實例字段在Java代碼中可以不賦初始值就直接使用。
操作完這步後,方法還沒有執行,所有的字段還爲零。一般來說,執行new指令後會接着執行方法,把對象按照程序員的意願進行初始化

對象的訪問定位

創建對象後如何使用對象,我們的Java程序需要通過棧上的reference數據來操作堆上的具體對象,由於reference類型在虛擬機規範中只規定了一個指向對象的引用,因此如何訪問堆中的對象的具體位置,也是取決於虛擬機實現而定.目前主流的訪問方式有使用句柄和直接指針兩種

使用句柄,Java堆中劃分一塊內存來作爲句柄池,reference中存儲的就是對象的句柄地址,句柄中包含了對象的實例數據與類型數據各自的具體地址信息.

這裏寫圖片描述

直接指針訪問,那麼Java堆對象的佈局中就必須考慮如何放置訪問類型數據的相關信息,而reference中存儲的直接就是對象地址

這裏寫圖片描述

使用句柄來訪問的最大好處就是reference中存儲的是穩定的句柄地址,在對象被移動時(垃圾收集時移動對象是非常普遍的行爲)只會改變句柄中的實例數據指針,而reference本身不需要修改

使用直接指針訪問的最大好處就是速度更快,它節省了一個指針定位的時間開銷,由於對象的訪問在Java中非常頻繁,因此這類開銷成本也非常可觀

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章