JVM - 剖析Java对象头Object Header之对象大小
文章目錄
- Pre
- 總覽
- 對(duì)象頭剖析
- 查看對(duì)象內(nèi)存的占用情況
- 對(duì)象頭C++源碼 注釋
Pre
JVM - 寫(xiě)了這么多年代碼,你知不道new對(duì)象背后的邏輯? 中大體介紹了Java中 new 對(duì)象背后的主要流程,其中對(duì)象頭的部分,我們僅僅是點(diǎn)到為止,這里我們深入剖一下Object Header的奧秘 。
總覽
初始化默認(rèn)值以后,JVM要對(duì)對(duì)象進(jìn)行必要的設(shè)置,例如這個(gè)對(duì)象是哪個(gè)類(lèi)的實(shí)例、如何才能找到類(lèi)的元數(shù)據(jù)信息、對(duì)象的哈希碼、對(duì)象的GC分代年齡等信息。這些信息存放在對(duì)象的對(duì)象頭Object Header之中。 這部分?jǐn)?shù)據(jù)的長(zhǎng)度在32位和64位的虛擬機(jī)中分別為32個(gè)和64個(gè)bits,官方稱(chēng)它為“Mark Word”。
在HotSpot虛擬機(jī)中,對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為3塊區(qū)域:對(duì)象頭(Header)、 實(shí)例數(shù)據(jù)(Instance Data)和和對(duì)齊填充(Padding) 。
HotSpot虛擬機(jī)的對(duì)象頭包括兩部分信息
- 第一部分用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù), 如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時(shí) 間戳等。
我們以32位操作系統(tǒng)的組成來(lái)看一下,下面這個(gè)圖也是從網(wǎng)上找的,感覺(jué)很清晰
- 對(duì)象頭的另外一部分是類(lèi)型指針,即對(duì)象指向它的類(lèi)元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類(lèi)的實(shí)例。
如下紅色框框中的示意圖
對(duì)象頭剖析
查看對(duì)象內(nèi)存的占用情況
推薦openjdk的jol工具, 可以查看對(duì)象內(nèi)存的占用情況。
添加依賴
<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 默認(rèn)開(kāi)啟的壓縮所有指針// -XX:+UseCompressedClassPointers 默認(rèn)開(kāi)啟的壓縮對(duì)象頭里的類(lèi)型指針Klass Pointer// Oops : Ordinary Object Pointerspublic static class ArtisanTest {//8B mark word//4B Klass Pointer 如果關(guān)閉壓縮-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,則占用8Bint id; //4BString name; //4B 如果關(guān)閉壓縮-XX:-UseCompressedOops,則占用8Bbyte b; //1BObject o; //4B 如果關(guān)閉壓縮-XX:-UseCompressedOops,則占用8B} }【輸出結(jié)果 】
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【結(jié)果說(shuō)明】
3中類(lèi)型 : new Object() | new int[]{}數(shù)組 | new ArtisanTest()
我這個(gè)電腦是64位的操作系統(tǒng),所以 mark word 占 8個(gè)字節(jié)。JDK8 klass point 默認(rèn)開(kāi)啟了指針壓縮,所以是4個(gè)字節(jié) , 不足8的倍數(shù)的,使用padding對(duì)齊填充,其目的是為了計(jì)算機(jī)高效尋址。
最后一個(gè),對(duì)于包含多個(gè)變量的對(duì)象的對(duì)象頭
對(duì)象頭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)總結(jié)
以上是生活随笔為你收集整理的JVM - 剖析Java对象头Object Header之对象大小的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: JVM - 写了这么多年代码,你还不知道
- 下一篇: JVM - 剖析Java对象头Objec