日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

JVM - 剖析Java对象头Object Header之对象大小

發(fā)布時(shí)間:2025/3/21 java 56 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM - 剖析Java对象头Object Header之对象大小 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • Pre
  • 總覽
  • 對(duì)象頭剖析
    • 查看對(duì)象內(nèi)存的占用情況
  • 對(duì)象頭C++源碼 注釋

Pre

JVM - 寫了這么多年代碼,你知不道new對(duì)象背后的邏輯? 中大體介紹了Java中 new 對(duì)象背后的主要流程,其中對(duì)象頭的部分,我們僅僅是點(diǎn)到為止,這里我們深入剖一下Object Header的奧秘 。


總覽

初始化默認(rèn)值以后,JVM要對(duì)對(duì)象進(jìn)行必要的設(shè)置,例如這個(gè)對(duì)象是哪個(gè)類的實(shí)例、如何才能找到類的元數(shù)據(jù)信息、對(duì)象的哈希碼、對(duì)象的GC分代年齡等信息。這些信息存放在對(duì)象的對(duì)象頭Object Header之中。 這部分?jǐn)?shù)據(jù)的長(zhǎng)度在32位和64位的虛擬機(jī)中分別為32個(gè)和64個(gè)bits,官方稱它為“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)的組成來看一下,下面這個(gè)圖也是從網(wǎng)上找的,感覺很清晰

  • 對(duì)象頭的另外一部分是類型指針,即對(duì)象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個(gè)指針來確定這個(gè)對(duì)象是哪個(gè)類的實(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)開啟的壓縮所有指針// -XX:+UseCompressedClassPointers 默認(rèn)開啟的壓縮對(duì)象頭里的類型指針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é)果說明】

3中類型 : new Object() | new int[]{}數(shù)組 | new ArtisanTest()

我這個(gè)電腦是64位的操作系統(tǒng),所以 mark word 占 8個(gè)字節(jié)。JDK8 klass point 默認(rèn)開啟了指針壓縮,所以是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ǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。