深入理解JVM:java對象的創建過程?

對象的創建過程

Step1:類加載檢查

虛擬機遇到一條 new 指令時,首先將去檢查這個指令的參數是否能在常量池中定位到這個類的符號引用,並且檢查這個符號引用代表的類是否已被加載過、解析和初始化過。如果沒有,那必須先執行相應的類加載過程。

Step2:分配內存

在類加載檢查通過後,接下來虛擬機將爲新生對象分配內存。對象所需的內存大小在類加載完成後便可確定,爲對象分配空間的任務等同於把一塊確定大小的內存從 Java 堆中劃分出來。分配方式有 “指針碰撞” 和 “空閒列表” 兩種,選擇那種分配方式由 Java 堆是否規整決定,而 Java 堆是否規整又由所採用的垃圾收集器是否帶有壓縮整理功能決定。

內存分配的兩種方式:

選擇以上兩種方式中的哪一種,取決於 Java 堆內存是否規整。而 Java 堆內存是否規整,取決於 GC 收集器的算法是"標記-清除",還是"標記-整理"(也稱作"標記-壓縮"),值得注意的是,複製算法內存也是規整的
參考:一張圖解釋指針碰撞和空閒列表
指針碰撞
空閒列表
內存分配併發問題

在創建對象的時候有一個很重要的問題,就是線程安全,因爲在實際開發過程中,創建對象是很頻繁的事情,作爲虛擬機來說,必須要保證線程是安全的,通常來講,虛擬機採用兩種方式來保證線程安全:

CAS+失敗重試: CAS 是樂觀鎖的一種實現方式。所謂樂觀鎖就是,每次不加鎖而是假設沒有衝突而去完成某項操作,如果因爲衝突失敗就重試,直到成功爲止。虛擬機採用 CAS 配上失敗重試的方式保證更新操作的原子性。
TLAB: 爲每一個線程預先在 Eden 區分配一塊兒內存,JVM 在給線程中的對象分配內存時,首先在 TLAB 分配,當對象大於 TLAB 中的剩餘內存或 TLAB 的內存已用盡時,再採用上述的 CAS 進行內存分配

Step3:初始化零值

內存分配完成後,虛擬機需要將分配到的內存空間都初始化爲零值(不包括對象頭),這一步操作保證了對象的實例字段在 Java 代碼中可以不賦初始值就直接使用,程序能訪問到這些字段的數據類型所對應的零值。

Step4:設置對象頭

初始化零值完成之後,虛擬機要對對象進行必要的設置,例如這個對象是那個類的實例、如何才能找到類的元數據信息、對象的哈希碼、對象的 GC 分代年齡等信息。 這些信息存放在對象頭中。 另外,根據虛擬機當前運行狀態的不同,如是否啓用偏向鎖等,對象頭會有不同的設置方式。

Step5:執行 < init >() 方法

在上面工作都完成之後,從虛擬機的視角來看,一個新的對象已經產生了,但從 Java 程序的視角來看,對象創建纔剛開始, 方法還沒有執行,所有的字段都還爲零。所以一般來說,執行 new 指令之後會接着執行< init >() 方法,把對象按照程序員的意願進行初始化,這樣一個真正可用的對象纔算完全產生出來。

對象引用的兩種實現方式
在這裏插入圖片描述

對象的內存佈局
參考:
對象的內存佈局

對象的內存佈局
java對象結構
在這裏插入圖片描述

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