JVM(三)JVM中對(duì)象的內(nèi)存布局詳解
2018年01月19日 23:21:47 B8613A 閱讀數(shù):513更多
所屬專欄: JVM 深入講解
<article class="baidu_pl" style="box-sizing: inherit; outline: 0px; margin: 0px; padding: 16px 0px 0px; display: block; position: relative; color: rgba(0, 0, 0, 0.75); font-family: -apple-system, "SF UI Text", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif; font-size: 14px; font-style: normal; font-variant-ligatures: common-ligatures; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">
版權(quán)聲明:本文為博主原創(chuàng)文章溉瓶,未經(jīng)博主允許不得轉(zhuǎn)載痹兜。 https://blog.csdn.net/liupeifeng3514/article/details/79111565
在前面我們了解了Java對(duì)象在JVM中的創(chuàng)建過(guò)程饰剥,接下來(lái)我們?cè)賮?lái)分析一下對(duì)象在JVM中的內(nèi)存布局葡公。
在HotSpot虛擬機(jī)中岩馍,對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為3塊區(qū)域:對(duì)象頭(Header)失息,實(shí)例數(shù)據(jù)( Instance Data)和對(duì)齊填充(Padding)薄榛。如下圖所示(原諒我盜用了兩張圖岔激。兩張圖是一樣的萎攒,只是表達(dá)方式不一樣遇八,大家看看哪個(gè)好記吧!):
[圖片上傳中...(image-9c9e0f-1559200018785-5)]
接下來(lái)我們分析其中的每一部分耍休。
一刃永、對(duì)象頭(Header)
HotSpot 虛擬機(jī)的對(duì)象頭包括兩部分(非數(shù)組對(duì)象)信息,如下圖所示:
- 第一部分用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù)羊精,如哈希碼(HashCode)斯够、GC 分代年齡、鎖狀態(tài)標(biāo)志喧锦、線程持有的鎖读规、偏向線程ID、偏向時(shí)間戳燃少、對(duì)象分代年齡束亏,這部分信息稱為“Mark Word”;Mark Word被設(shè)計(jì)成一個(gè)非固定的數(shù)據(jù)結(jié)構(gòu)以便在極小的空間內(nèi)存儲(chǔ)盡量多的信息阵具,它會(huì)根據(jù)自己的狀態(tài)復(fù)用自己的存儲(chǔ)空間碍遍;
- 第二部分是類型指針,即對(duì)象指向它的類元數(shù)據(jù)的指針阳液,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例怕敬;
- 如果對(duì)象是一個(gè) Java 數(shù)組,那在對(duì)象頭中還必須有一塊用于記錄數(shù)組長(zhǎng)度的數(shù)據(jù)帘皿。因?yàn)樘摂M機(jī)可以通過(guò)普通 Java 對(duì)象的元數(shù)據(jù)信息確定Java 對(duì)象的大小东跪,但是從數(shù)組的元數(shù)據(jù)中無(wú)法確定數(shù)組的大小。這部分?jǐn)?shù)據(jù)的長(zhǎng)度在 32 位和 64 位的虛擬機(jī)(未開(kāi)啟壓縮指針)中分別為32bit 和 64bit。
例如虽填,在 32 位的 HotSpot 虛擬機(jī)中丁恭,如果對(duì)象處于未被鎖定的狀態(tài)下,那么 Mark Word 的 32bit 空間中的 25bit 用于存儲(chǔ)對(duì)象哈希碼卤唉,4bit 用于存儲(chǔ)對(duì)象分代年齡涩惑,2bit 用于存儲(chǔ)鎖標(biāo)志位仁期,1bit 固定為 0桑驱,如下表所示:
而在其他狀態(tài)(輕量級(jí)鎖定、重量級(jí)鎖定跛蛋、cc標(biāo)記熬的、可偏向)下對(duì)象的存儲(chǔ)內(nèi)容見(jiàn)下表:
代碼清單2-2為HotSpot虛擬機(jī)markOop.cpp中的代碼(注釋)片段,它描述了32bit下Mark Word的存儲(chǔ)狀態(tài)赊级。
二押框、實(shí)例數(shù)據(jù)(Instance Data)
實(shí)例數(shù)據(jù)部分是對(duì)象真正存儲(chǔ)的有效信息,也既是我們?cè)诔绦虼a里面所定義的各種類型的字段內(nèi)容理逊,無(wú)論是從父類繼承下來(lái)的橡伞,還是在子類中定義的都需要記錄下來(lái)。
這部分的存儲(chǔ)順序會(huì)受到虛擬機(jī)分配策略參數(shù)(FieldsAllocationStyle)和字段在Java源碼中定義順序的影響晋被。
HotSpot虛擬機(jī)默認(rèn)的分配策略為longs/doubles兑徘、ints、shorts/chars羡洛、bytes/booleans挂脑、oops(Ordinary Object Pointers),從分配策略中可以看出欲侮,相同寬度的字段總是被分配到一起崭闲。在滿足這個(gè)前提條件的情況下,在父類中定義的變量會(huì)出現(xiàn)在子類之前威蕉。如果 CompactFields參數(shù)值為true(默認(rèn)為true)刁俭,那子類之中較窄的變量也可能會(huì)插入到父類變量的空隙之中。
三韧涨、對(duì)齊填充(Padding)
對(duì)齊填充并不是必然存在的薄翅,也沒(méi)有特別的含義,它僅僅起著占位符的作用氓奈。由于HotSpot VM的自動(dòng)內(nèi)存管理系統(tǒng)要求對(duì)象起始地址必須是8字節(jié)的整數(shù)倍翘魄,換句話說(shuō)就是對(duì)象的大小必須是8字節(jié)的整數(shù)倍。對(duì)象頭正好是8字節(jié)的倍數(shù)(1倍或者2倍)舀奶,因此當(dāng)對(duì)象實(shí)例數(shù)據(jù)部分沒(méi)有對(duì)齊的話暑竟,就需要通過(guò)對(duì)齊填充來(lái)補(bǔ)全。
接下來(lái)我們看一個(gè)【估算對(duì)象大小】的小例子(好吧,這也是我從其他地方看來(lái)的_!)但荤。
32 位系統(tǒng)下罗岖,當(dāng)使用 new Object() 時(shí),JVM 將會(huì)分配 8(Mark Word+類型指針) 字節(jié)的空間腹躁,128 個(gè) Object 對(duì)象將占用 1KB 的空間桑包。如果是 new Integer(),那么對(duì)象里還有一個(gè) int 值纺非,其占用 4 字節(jié)哑了,這個(gè)對(duì)象也就是 8+4=12 字節(jié),對(duì)齊后烧颖,該對(duì)象就是 16 字節(jié)弱左。
以上只是一些簡(jiǎn)單的對(duì)象,那么對(duì)象的內(nèi)部屬性是怎么排布的炕淮?
Class A {
int i;
byte b;
String str;
}
其中對(duì)象頭部占用 ‘Mark Word’4 + ‘類型指針’4 = 8 字節(jié)拆火;byte 8 位長(zhǎng),占用 1 字節(jié)涂圆;int 32 位長(zhǎng)们镜,占用 4 字節(jié);String 只有引用润歉,占用 4 字節(jié)模狭;那么對(duì)象 A 一共占用了 8+1+4+4=17 字節(jié),按照 8 字節(jié)對(duì)齊原則卡辰,對(duì)象大小也就是 24 字節(jié)胞皱。
這個(gè)計(jì)算看起來(lái)是沒(méi)有問(wèn)題的,對(duì)象的大小也確實(shí)是 24 字節(jié)九妈,但是對(duì)齊(padding)的位置并不對(duì):在 HotSpot VM 中反砌,對(duì)象排布時(shí),間隙是在 4 字節(jié)基礎(chǔ)上的(在 32 位和 64 位壓縮模式下)萌朱。上述例子中宴树,int 后面的 byte,空隙只剩下 3 字節(jié)晶疼,接下來(lái)的 String 對(duì)象引用需要 4 字節(jié)來(lái)存放酒贬,因此 byte 和對(duì)象引用之間就會(huì)有 3 字節(jié)對(duì)齊,對(duì)象引用排布后翠霍,最后會(huì)有 4 字節(jié)對(duì)齊锭吨,因此結(jié)果上依然是 7 字節(jié)對(duì)齊。此時(shí)對(duì)象的結(jié)構(gòu)示意圖寒匙,如下圖所示:
</article>