天天看點

Java記憶體區域對象的記憶體布局和通路定位(Header、Instance、Padding)

Java普通對象被建立出以後,就需要關注下它在JVM堆中的記憶體布局是什麼樣子的。

大緻分為3個區域:

1.對象頭(Header)

2.執行個體資料(Instance)

3.對齊補充(Padding)

對象頭在JVM這本書中有個專門的章節去講Class檔案的布局,這一章還沒有去看,是以,對于這個暫時沒有什麼概念。

主要分為2部分:

1)存儲對象自身的運作時資料(Mark Word)

常見的包括hash碼,GC年齡,鎖狀态标志,線程持有的鎖,偏向線程ID,偏向時間戳等等。

具體布局我不想關注了,先知道下是什麼,之後再去想為什麼。

2)存儲指向對象類型資料的指針

這個指針就是确定這個對象是哪個類的執行個體。 但是書中說這個不是必須的,需要對應對象的通路方式

存在的意義在于,棧中對象的引用使用直接指針的時候,該指針指向堆記憶體中的對象,是以對象頭是需要存儲它的類雲資料指針,這個指針才是指向方法區中對象的類型 資料。

3)Java數組是特例

當是數組時還需要記錄數組長度,這是因為數組對象類型的資料中沒有數組長度資訊。

對象存儲的真正有效的資料,也就是程式代碼中所定義的各種類型字段内容。包括父類繼承的和子類定義的。

說下存儲順序:

1).受到JVM配置設定政策影響(FieldsAllocationStyle)

longs/doubles、

ints、

shorts/chars、

bytes/booleans、

oops(Ordinary Object Pointers) 差不多相同長度的被分在一塊。

2).字段在Java源碼中定義順序影響

對齊補充不是必須存在的,就是占位的作用。不去管它。

對象的通路定位

相信大家都是知道,一個對象的通路,是通過棧中的引用 通路堆中具體的位址擷取到這個對象的,但是JVM并沒有規定需要用何種方式去定位這個對象的具體位置。

目前主流的方式是兩種:

1).句柄

2).直接指針

Java記憶體區域對象的記憶體布局和通路定位(Header、Instance、Padding)

本質還是通過棧去通路,但是在堆中多出一塊區域,存放的是句柄池,reference中存放的是對象的句柄位址,而不是真正對象的位址。句柄池記憶體放着對象執行個體資料與類型資料各自的位址,

優勢: reference中存儲的是穩定的句柄位址,在對象被移動(進行垃圾處理時)隻改變句柄中的執行個體資料指針,而reference不需要修改。

Java記憶體區域對象的記憶體布局和通路定位(Header、Instance、Padding)

如果使用了直接位址,那麼從圖中也可見對象裡面需要存放了類型資料的相關資訊。

優勢: 速度更快,省去通過句柄的另一次開銷,這是常見的通路對象的方式。

繼續閱讀