1. 程式人生 > >JVM:HotSpot物件探祕-建立、記憶體分配、訪問定位

JVM:HotSpot物件探祕-建立、記憶體分配、訪問定位

今天來研究一下HotSpot中物件的建立以及記憶體分配、訪問定位。

如何建立物件?

在java語言層面,通過new關鍵字建立物件,
現在要探究的是虛擬機器內建立物件的過程:
1、當遇到new指令時,先根據這個指令的引數去常量池中查詢是否有對應一個類的符號引用。
2、檢查這個符號引用所代表的類是否載入初始化過,如果沒有,則執行載入初始化的過程。
3、類載入檢查通過後,虛擬機器將為新生物件分配記憶體空間。
– 3.1 注意,在類載入完成後,物件的大小就已經可以確定下來,為新生物件分配記憶體空間,就是從記憶體中分配指定大小的空間。
為物件分配記憶體的方式有兩種
– 3.2.1 指標碰撞
適用場景:記憶體規整,已分配的在一邊,空閒的在另一邊,中間有一個指示分界點的指標。
分配原理:把指標往空閒方向移動物件大小的距離
– 3.2.2 空閒列表
適用場景:記憶體不規整,已分配和空閒的記憶體空間交錯,維護一個空閒記憶體的列表
分配原理:在空閒記憶體的列表裡找到一個足夠大的記憶體空間分配給物件,並更新列表的記錄。

注意:具體使用哪一種方式給物件分配記憶體,取決於垃圾回收的演算法是否帶有壓縮整理的功能。

4、在為物件完成記憶體分配後,會初始化物件的例項資料都為零值。
5、設定物件的物件頭,包括鎖標誌、GC分代年齡、hashCode、屬於哪個類的例項,如何才能找到元資料資訊
6、new指令後執行<init>方法,按照程式碼進行初始化,完成一個物件的建立

物件的建立在虛擬機器內是非常頻繁的行為,需要考慮他是否執行緒安全?虛擬機器是怎麼解決的?

1、是否安全
理論上不是執行緒安全的。因為在給A物件分配記憶體的時候,可以指標還沒有移好,B物件也參與到記憶體分配,這時候就會亂套
2、怎麼解決?
2.1 、 CAS+失敗重試保證指標更新操作的原子性[虛擬機器預設採用]
2.2、TLAB :為每個執行緒事先分配一些記憶體空間,這個執行緒裡物件的記憶體分配都在這一段空間內操作。當這個執行緒內的空間用完了,才需要通過CAS去分配新的空間。[在分配TLAB時就會初始化零值]

物件的記憶體佈局

物件包含 物件頭、例項資料、對齊填充
1、物件頭,鎖標誌、GC分代年齡、hashCode、鎖偏向ID、執行緒持有的鎖、型別指標
2、例項資料:儲存的具體資料
3、對齊填充:物件大小要求8位元組的倍數,沒有對齊就補全

如何實現物件的訪問定位?

在java中,我們可以通過棧中的引用來找到分配在堆中的物件,這裡來看下,物件的訪問定位如何實現?
有兩種 控制代碼和直接指標
1、控制代碼:
在java堆中會劃分出一塊記憶體作為控制代碼池,棧中的引用就是物件的控制代碼的引用,控制代碼持有物件例項資料地址和物件類資訊的地址。

優點:GC過程中移動物件,只需要改變控制代碼中的物件例項資料地址,而不需要改棧中的引用。
缺點:兩次指標定位,積少成多,有一定的開銷成本

2、直接指標:
棧中的引用直接指向堆中物件的地址。這種訪問定位方式要求物件頭中包含物件的型別指標。

優點:一次指標定位即可
缺點:GC過程中移動物件,需要修改棧中的引用。

HotSpot使用第二種方式