溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java object對象在heap中的結(jié)構(gòu)是什么

發(fā)布時(shí)間:2021-10-23 15:44:49 來源:億速云 閱讀:165 作者:柒染 欄目:大數(shù)據(jù)

java object對象在heap中的結(jié)構(gòu)是什么,很多新手對此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。      

簡介

在之前的文章中,我們介紹了使用JOL這一神器來解析java類或者java實(shí)例在內(nèi)存中占用的空間地址。


今天,我們會(huì)更進(jìn)一步,剖析一下在之前文章中沒有講解到的更深層次的細(xì)節(jié)。一起來看看吧。

對象和其隱藏的秘密

java.lang.Object大家應(yīng)該都很熟悉了,Object是java中一切對象的鼻祖。


接下來我們來對這個(gè)java對象的鼻祖進(jìn)行一個(gè)詳細(xì)的解剖分析,從而理解JVM的深層次的秘密。


工具當(dāng)然是使用JOL:


@Slf4jpublic class JolUsage {
   @Test    public void useJol(){        log.info("{}", VM.current().details());  log.info("{}", ClassLayout.parseClass(Object.class).toPrintable());        log.info("{}", ClassLayout.parseInstance(new Object()).toPrintable());    }}


代碼很簡單,我們打印JVM的信息,Object class和一個(gè)新的Object實(shí)例的信息。


看下輸出:

java object對象在heap中的結(jié)構(gòu)是什么


從上面的結(jié)果我們知道,在64位的JVM中,一個(gè)Object實(shí)例是占用16個(gè)字節(jié)。


因?yàn)镺bject對象中并沒有其他對象的引用,所以我們看到Object對象只有一個(gè)12字節(jié)的對象頭。剩下的4個(gè)字節(jié)是填充位。


Object對象頭

那么這12字節(jié)的對象頭是做什么用的呢?


如果想要深入了解這12字節(jié)的對象頭,當(dāng)然是要去研讀一下JVM的源碼:src/share/vm/oops/markOop.hpp。


有興趣的小伙伴可以去看看。如果沒有興趣,沒關(guān)系,這里給大家一個(gè)張總結(jié)的圖:

java object對象在heap中的結(jié)構(gòu)是什么


javaObject對象的對象頭大小根據(jù)你使用的是32位還是64位的虛擬機(jī)的不同,稍有變化。這里我們使用的是64位的虛擬機(jī)為例。


Object的對象頭,分為兩部分,第一部分是Mark Word,用來存儲(chǔ)對象的運(yùn)行時(shí)數(shù)據(jù)比如:hashcode,GC分代年齡,鎖狀態(tài),持有鎖信息,偏向鎖的thread ID等等。


在64位的虛擬機(jī)中,Mark Word是64bits,如果是在32位的虛擬機(jī)中Mark Word是32bits。


第二部分就是Klass Word,Klass Word是一個(gè)類型指針,指向class的元數(shù)據(jù),JVM通過Klass Word來判斷該對象是哪個(gè)class的實(shí)例。


且慢!


有的小伙伴可能發(fā)現(xiàn)了問題,之前我們用JOL解析Object對象的時(shí)候,Object head大小是12字節(jié),也就是96bits,這里怎么寫的是128bits?

java object對象在heap中的結(jié)構(gòu)是什么


沒錯(cuò),如果沒有開啟COOPs就是128bits,如果開啟了COOPs,那么Klass Word的大小就從64bits降到了32bits。


還記得我們之前講的COOPs嗎?


COOPs就是壓縮對象指針技術(shù)。


對象指針用來指向一個(gè)對象,表示對該對象的引用。通常來說在64位機(jī)子上面,一個(gè)指針占用64位,也就是8個(gè)字節(jié)。而在32位機(jī)子上面,一個(gè)指針占用32位,也就是4個(gè)字節(jié)。


實(shí)時(shí)上,在應(yīng)用程序中,這種對象的指針是非常非常多的,從而導(dǎo)致如果同樣一個(gè)程序,在32位機(jī)子上面運(yùn)行和在64位機(jī)子上面運(yùn)行占用的內(nèi)存是完全不同的。64位機(jī)子內(nèi)存使用可能是32位機(jī)子的1.5倍。


而壓縮對象指針,就是指把64位的指針壓縮到32位。


怎么壓縮呢?64位機(jī)子的對象地址仍然是64位的。壓縮過的32位存的只是相對于heap base address的位移。


我們使用64位的heap base地址+ 32位的地址位移量,就得到了實(shí)際的64位heap地址。


對象指針壓縮在Java SE 6u23 默認(rèn)開啟。在此之前,可以使用-XX:+UseCompressedOops來開啟。


數(shù)組對象頭

java中有一個(gè)非常特別的對象叫做數(shù)組,數(shù)組的對象頭和Object有什么區(qū)別嗎?


我們用JOL再看一次:

log.info("{}",ClassLayout.parseClass(byte[].class).toPrintable());log.info("{}",ClassLayout.parseInstance("www.flydean.com".getBytes()).toPrintable());

上面的例子中我們分別解析了byte數(shù)組的class和byte數(shù)組的實(shí)例:


java object對象在heap中的結(jié)構(gòu)是什么


看到區(qū)別了嗎?我們發(fā)現(xiàn)數(shù)組的對象頭是16字節(jié),比普通對象的對象頭多出了4個(gè)字節(jié)。這4個(gè)字節(jié)就是數(shù)組的長度。


整個(gè)對象的結(jié)構(gòu)

好了,寫到這里我們來總結(jié)一下,java對象的結(jié)構(gòu)可以分為普通java對象和數(shù)組對象兩種:


數(shù)組對象在對象頭中多了一個(gè)4字節(jié)的長度字段。


大家看到最后的字節(jié)是padding填充字節(jié),為什么要填充呢?


因?yàn)镴VM是以8字節(jié)為單位進(jìn)行對其的,如果不是8字節(jié)的整數(shù)倍,則需要補(bǔ)全。

更多精彩內(nèi)容

1

看動(dòng)畫學(xué)算法之:排序-歸并排序

2

計(jì)算機(jī)揭秘之:網(wǎng)絡(luò)分類和性能分析

3

JVM詳解之:運(yùn)行時(shí)常量池

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI