JVM 如何創建Java對象

在Java程序中,創建一個對象通常需要一個new關鍵字就夠了,但是在虛擬機中,這個過程卻有點複雜,這裏麪包括了類加載、內存分配、初始化零值等等一系列的步驟。

下面來看看JVM如何創建一個對象(這裏面的對象僅僅限於不同的Java對象,不包括數組和Class對象)

1 對象的創建

1.1 類初始化

當JVM遇到一條new的指令(與new關鍵字不是一個概念)時,首先去檢查這個指令是否在常量池中定位到一個類的符號引用,並且檢查這個符號引用代表的類是否已經加載、解析和初始化過。如果沒有,那麼必須先執行類的初始化工作。

1.2 劃分空間

接下來就是要堆中劃分出一塊空間,這塊空間的大小由類去確定,在類加載以後,一個對象的大小已經是確定的了。對於這個劃分,可能存在兩種情況

(1)堆的空間是規整的,已用過的部分在一邊,未用過的部分在另外一邊,有一個指針指向未使用部分的頭,每次移動這個指針就可以了,這種方法稱爲“指針碰撞”

(2) 堆的空間是零散的,使用和未使用的部分交叉排列,這時候就需要一個維護一個列表,記錄哪些內存是可用的,在分配的時候找到一塊足夠大的內存進行分配,這種方法稱爲“空閒列表”。很顯然這種方式會產生很多內存碎片

實際中採用哪種分配方式是由虛擬機採用的垃圾收集算法決定的,主要取決於垃圾收集器是否帶有壓縮整理功能(campact)。因此,在使用Serial,ParNew等待Compact過程的收集器時,系統採用指針碰撞,而使用CMS這種基於Mark-Sweep算法的收集器時,採用空閒列表。

如何保證對象創建的線程安全性?

對象創建是虛擬機中頻繁發生的行爲,移動指針時如何保證線程安全呢?這個問題有兩個解決方法

1 採用CAS+失敗重試保證更新操作證的原子性

2 把內存分配動作按照線程劃分在不同空間中進行。在堆中爲每個內存分配一小塊空間,稱爲本地線程分配緩衝(TLAB)。線程分配內存時,在自己的TLAB上分配,當TLAB使用完時,使用同步鎖。

1.3 賦零值

內存分配完成後,虛擬機把分配到的內存空間初始化爲零值,如果使用TLAB,這一過程在TLAB中進行。這一步保證了Java的實例字段在Java代碼中不同賦值就可以使用

1.4 設置對象頭

虛擬機啊要對對象進行必要的設置,例如對象時哪個類的實例、如何才能找到類的元數據信息、對象的哈希碼、對象的GC分代年齡等信息。這些信息保存在對象頭中。

1.5 <init>指令

在上面的工作完成後,對於虛擬機來說,一個對象已經創建完成,帶從Java對象的角度,還沒有進行初始化,<init>方法還沒有執行,所有的字段都還是零值。這個<init>方法可以理解爲對象的構造方法

2 對象的內存佈局

在HotSpot虛擬機中,對象在內存中儲存的佈局分爲3個部分:對象頭(Header)、實例數據(Instance Data) 和對其填充

2.1 對象頭

對象頭包括兩個部分,第一個部分用於儲存對象自身的運行時數據,這個部分的長度在32位和64位的虛擬機中分別爲32bit和64bit,官方稱爲“Mark Word”。對象頭被設計稱爲與對象結構無關的一個數據結構,32bit的儲存內容如下:

HotSpot虛擬機對象頭
存儲內容 標誌位 狀態
對象哈希碼、對象分代信息 01 未鎖定
指向鎖記錄的指針 00 輕量級鎖定
指向重量鎖的指針 10 重量級鎖定
空,不需要記錄i信息 11 GC標記
偏向線程ID、偏向時間戳、對象分代信息 01 可偏向
對象頭的另一個部分是類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針確定這個對象指向哪個類的實例。並不是所有虛擬機實現都必須在對象數據上保留這個類型指針,也就說,查找對象的元數據信息並不一定要經過對象本身。另外,如果對象是一個數組,那對象頭必須還有一塊用於記錄數組長度的數據。

2.2 實例數據域

這個部分是對象真正存儲的有效信息,也就是程序代碼中所定義的各種類型的字段內容。無論是從父類繼承下來的,還是子類中定義的,都需要記錄起來。這部分的儲存順序受到虛擬機分配策略參數和字段在Java源碼中定義的順序的影響。HotSpot虛擬機默認的分配策略爲long/doubles、ints、shorts/chars,bytes/booleans、oops,從分配策略來看,相同寬度的字段總是被分配在一起。在滿足這個前提下,父類的變量會出現在子類之前。如果指定了compactFileds參數爲true,那麼子類之中較窄的變量可能會插入到父類變量的空隙之中。

2.3對齊填充

這個部分並不一定有,而且沒有什麼實際意義,僅僅是爲了填充數據。HotSpot VM的自動內存管理系統要求對象起始地址必須是8字節的整數倍,也就是每個對象佔得大小必須是8字節的整數倍,如果實例域不滿足,就要補充對其。




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