1. 程式人生 > >對象內存布局與訪問

對象內存布局與訪問

-s size 布局 數組長度 引用 修改 hot 記錄 理解

對象內存布局

在HotSpot虛擬機中,對象在內存中存儲的布局可以分為3塊區域:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)。

對象頭

HotSpot虛擬機的對象頭包括兩部分信息:運行時數據和類型指針。

運行時數據

用於存儲對象自身的運行時數據,如哈希碼(HashCode)、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID、偏向時間戳等。

技術分享

類型指針

即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。

如果對象是一個Java數組,那在對象頭中還必須有一塊用於記錄數組長度的數據,因為虛擬機可以通過普通Java對象的元數據信息確定Java對象的大小,但是從數組的元數據中無法確定數組的大小。
(並不是所有的虛擬機實現都必須在對象數據上保留類型指針,換句話說,查找對象的元數據並不一定要經過對象本身,可參考對象的訪問定位)

實例數據

實例數據部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內容。無論是從父類中繼承下來的,還是在子類中定義的,都需要記錄下來。HotSpot虛擬機默認的分配策略為longs/doubles、ints、shorts/chars、bytes/booleans、oop,從分配策略中可以看出,相同寬度的字段總是分配到一起。

對齊填充

HotSpot虛擬機要求對象的起始地址必須是8字節的整數倍,也就是對象的大小必須是8字節的整數倍。而對象頭部分正好是8字節的倍數(1倍或者2倍),因此,當對象實例數據部分沒有對齊的時候,就需要通過對齊填充來補全。

對象訪問定位

Java程序需要通過棧上的引用數據來操作堆上的具體對象。對象的訪問方式取決於虛擬機實現,目前主流的訪問方式有使用句柄和直接指針兩種。

句柄,可以理解為指向指針的指針,維護指向對象的指針變化,而對象的句柄本身不發生變化;指針,指向對象,代表對象的內存地址。

句柄
Java堆中劃分出一塊內存來作為句柄池,引用中存儲對象的句柄地址,而句柄中包含了對象實例數據與類型數據各自的具體地址信息。

技術分享

優勢:引用中存儲的是穩定的句柄地址,在對象被移動(垃圾收集時移動對象是非常普遍的行為)時只會改變句柄中的實例數據指針,而引用本身不需要修改。

直接指針

如果使用直接指針訪問,那麽Java堆對象的布局中就必須考慮如何放置訪問類型數據的相關信息,而引用中存儲的直接就是對象地址。

技術分享

優勢:速度更快,節省了一次指針定位的時間開銷。由於對象的訪問在Java中非常頻繁,因此這類開銷積少成多後也是非常可觀的執行成本。(例如HotSpot)

對象內存布局與訪問