深入理解Java虛擬機器之物件的記憶體佈局、訪問定位
記憶體佈局
在HotSpot虛擬機器中,物件在記憶體中儲存的佈局可以分為三塊區域:物件頭(Header)、例項資料(Instance Data)、對齊填充(Padding)。
物件頭
物件頭分為兩個部分,第一部分儲存自身的 執行時資料 ,如物件的雜湊碼、GC分代年齡、鎖標誌位等。這部分資料的長度在32位和64位的虛擬機器中分別為32bit和64bit,官方稱它為“Mark World”,Mark Word被設計為一個非固定的資料結構,以便在極小的記憶體空間記憶體儲儘量多的資訊,它會根據物件的狀態複用自己的儲存空間。32位HotSpot虛擬機器物件頭Mark Word儲存內容如下:
第二部分是 型別指標 ,即物件指向它的類元資料的指標,虛擬機器通過這個指標來確定這個物件是哪個類的例項。
如果物件是一個Java陣列,物件頭中還必須有一塊用於記錄陣列長度的資料,因為虛擬機器可以通過普通Java物件的元資料資訊確定Java物件的大小,但從陣列的元資料卻無法確定陣列的大小。
例項資料
例項資料部分是物件真正儲存的有效資訊,也是程式程式碼中所定義的各種型別的欄位內容。無論是從父類繼承下來的,還是在子類中定義的,都需要記錄下來。這部分的儲存順序會受到虛擬機器分配策略引數(FieldsAllocationStyle)和Java欄位在Java原始碼中定義的順序的影響。HotSpot虛擬機器預設的分配策略為longs/doubles、ints、shorts/chars、bytes/boolean、oops(ordinary object pointers),相同寬度的欄位總是被分配到一起。
對齊填充
對齊填充並不是必然存在的,僅起著佔位符的作用。由於HotSpot VM的自動記憶體管理系統要求物件的起始地址必須是8位元組的整倍數,而物件頭剛好是8位元組的整倍數,所以當物件例項資料部分沒有對齊時,就需要通過對齊填充來補全。
訪問定位
建立物件是為了使用物件,我們的Java程式需要通過棧上的reference資料來操作堆上的具體物件。
訪問方式
-
控制代碼訪問 :在堆中劃分出一塊記憶體來作為控制代碼池,reference中儲存的就是物件的控制代碼地址,控制代碼中包含了物件例項資料與型別資料各自的地址資訊。
-
直接指標訪問 :reference中儲存內容為物件地址。
兩種訪問方式優勢對比
控制代碼訪問最大的好處是reference中儲存的是穩定的控制代碼地址,在物件被移動時只會改變控制代碼中的例項資料的指標,而無需修改reference本身。
直接指標訪問的最大好處是速凍更快,節省了一次指標定位的時間開銷。