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).直接指針

本質還是通過棧去通路,但是在堆中多出一塊區域,存放的是句柄池,reference中存放的是對象的句柄位址,而不是真正對象的位址。句柄池記憶體放着對象執行個體資料與類型資料各自的位址,
優勢: reference中存儲的是穩定的句柄位址,在對象被移動(進行垃圾處理時)隻改變句柄中的執行個體資料指針,而reference不需要修改。
如果使用了直接位址,那麼從圖中也可見對象裡面需要存放了類型資料的相關資訊。
優勢: 速度更快,省去通過句柄的另一次開銷,這是常見的通路對象的方式。