JVM - 剖析Java对象头Object Header之对象大小
文章目錄
- Pre
- 總覽
- 對象頭剖析
- 查看對象內存的占用情況
- 對象頭C++源碼 注釋
Pre
JVM - 寫了這么多年代碼,你知不道new對象背后的邏輯? 中大體介紹了Java中 new 對象背后的主要流程,其中對象頭的部分,我們僅僅是點到為止,這里我們深入剖一下Object Header的奧秘 。
總覽
初始化默認值以后,JVM要對對象進行必要的設置,例如這個對象是哪個類的實例、如何才能找到類的元數據信息、對象的哈希碼、對象的GC分代年齡等信息。這些信息存放在對象的對象頭Object Header之中。 這部分數據的長度在32位和64位的虛擬機中分別為32個和64個bits,官方稱它為“Mark Word”。
在HotSpot虛擬機中,對象在內存中存儲的布局可以分為3塊區域:對象頭(Header)、 實例數據(Instance Data)和和對齊填充(Padding) 。
HotSpot虛擬機的對象頭包括兩部分信息
- 第一部分用于存儲對象自身的運行時數據, 如哈希碼(HashCode)、GC分代年齡、鎖狀態標志、線程持有的鎖、偏向線程ID、偏向時 間戳等。
我們以32位操作系統的組成來看一下,下面這個圖也是從網上找的,感覺很清晰
- 對象頭的另外一部分是類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。
如下紅色框框中的示意圖
對象頭剖析
查看對象內存的占用情況
推薦openjdk的jol工具, 可以查看對象內存的占用情況。
添加依賴
<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.10</version </dependency>示例
import org.openjdk.jol.info.ClassLayout;/*** @author 小工匠* @version v1.0* @create 2020-06-25 16:21* @motto show me the code ,change the word* @blog https://artisan.blog.csdn.net/* @description**/public class ObjectHeaderTest {public static void main(String[] args) {ClassLayout layout = ClassLayout.parseInstance(new Object());System.out.println(layout.toPrintable());System.out.println();ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});System.out.println(layout1.toPrintable());System.out.println();ClassLayout layout2 = ClassLayout.parseInstance(new ArtisanTest());System.out.println(layout2.toPrintable());}// -XX:+UseCompressedOops 默認開啟的壓縮所有指針// -XX:+UseCompressedClassPointers 默認開啟的壓縮對象頭里的類型指針Klass Pointer// Oops : Ordinary Object Pointerspublic static class ArtisanTest {//8B mark word//4B Klass Pointer 如果關閉壓縮-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,則占用8Bint id; //4BString name; //4B 如果關閉壓縮-XX:-UseCompressedOops,則占用8Bbyte b; //1BObject o; //4B 如果關閉壓縮-XX:-UseCompressedOops,則占用8B} }【輸出結果 】
java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total[I object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)16 0 int [I.<elements> N/A Instance size: 16 bytes Space losses: 0 bytes internal + 0 bytes external = 0 bytes totalcom.gof.test.ObjectHeaderTest$ArtisanTest object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 63 cc 00 f8 (01100011 11001100 00000000 11111000) (-134165405)12 4 int ArtisanTest.id 016 1 byte ArtisanTest.b 017 3 (alignment/padding gap) 20 4 java.lang.String ArtisanTest.name null24 4 java.lang.Object ArtisanTest.o null28 4 (loss due to the next object alignment) Instance size: 32 bytes Space losses: 3 bytes internal + 4 bytes external = 7 bytes totalProcess finished with exit code 0【結果說明】
3中類型 : new Object() | new int[]{}數組 | new ArtisanTest()
我這個電腦是64位的操作系統,所以 mark word 占 8個字節。JDK8 klass point 默認開啟了指針壓縮,所以是4個字節 , 不足8的倍數的,使用padding對齊填充,其目的是為了計算機高效尋址。
最后一個,對于包含多個變量的對象的對象頭
對象頭C++源碼 注釋
Bit‐format of an object header (most significant first, big endian layout below): // // 32 bits: // ‐‐‐‐‐‐‐‐ // hash:25 ‐‐‐‐‐‐‐‐‐‐‐‐>| age:4 biased_lock:1 lock:2 (normal object) // JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object) // size:32 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>| (CMS free block) // PromotedObject*:29 ‐‐‐‐‐‐‐‐‐‐>| promo_bits:3 ‐‐‐‐‐>| (CMS promoted object) // // 64 bits: // ‐‐‐‐‐‐‐‐ // unused:25 hash:31 ‐‐>| unused:1 age:4 biased_lock:1 lock:2 (normal object) // JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object) // PromotedObject*:61 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>| promo_bits:3 ‐‐‐‐‐>| (CMS promoted object) // size:64 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>| (CMS free block) // // unused:25 hash:31 ‐‐>| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object) // JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object) // narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ‐‐‐‐‐>| (COOPs && CMS promoted object) // unused:21 size:35 ‐‐>| cms_free:1 unused:7 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>| (COOPs && CMS free block)總結
以上是生活随笔為你收集整理的JVM - 剖析Java对象头Object Header之对象大小的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM - 写了这么多年代码,你还不知道
- 下一篇: JVM - 剖析Java对象头Objec