1. 程式人生 > 實用技巧 >java物件的儲存結構和指標壓縮學習

java物件的儲存結構和指標壓縮學習

HotSpot虛擬機器裡,物件在堆記憶體中的儲存不懼可以劃分為三個部分:

物件頭(Header)、例項資料(Instance Data)和對齊填充(Padding)。

物件頭包含了Mark Word(一定存在),元資料指標(一定存在),陣列size(如果這個物件是個陣列物件的話)。

例項資料:類元資訊中定義的變數資料

對齊填充可能存在的部分,同對象頭一樣,為了8位元組對齊的無實際意義填充部分。

64位虛擬機器來說,低於32G記憶體,預設開啟指標壓縮,那麼堆中的物件是這樣子的。

可以使用jol包來觀察物件的儲存結構,引入pom檔案
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10
</version> </dependency>

1)檢視物件內部資訊:ClassLayout.parseInstance(obj).toPrintable()

2)檢視物件佔用空間總大小:GraphLayout.parseInstance(obj).totalSize() 一個空的Object物件,64位虛擬機器開啟指標壓縮(預設開啟或者VM -options設定下 -XX:+UseCompressedOops開啟)

3)測試

package com.test.demo.test.jvm;

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.info.GraphLayout;

/** * @program: demo * @description: 檢視物件記憶體 空物件一般16b(沒有普通屬性的類生成的物件) * -XX:+UseCompressedOops開啟指標壓縮(預設) oop物件指標 * -XX:-UseCompressedOops關閉指標壓縮 * 指標壓縮的原理: * 指標不再表示物件在記憶體中的精確位置,而是表示偏移量。這意味著32位的指標可以引用40億個物件, * 而不是40億個位元組。最終,也就是說記憶體增長到32GB的實體記憶體,也可以用32位的指標表示。也就是說,我們只需要 * 知道JVM記憶體的開始位置,知道偏移量,就可以算出我想要找的實際物理位置。 ---------------物件頭區域-----------例項資料區域---------對齊填充區域(保證8的倍數) markword( 32位 4byte ---64位 8byte) class指標(開啟指標壓縮 4byte 關閉 8byte) 陣列物件(開啟指標壓縮 4byte 關閉 8byte) * @author: zhugaopo * @slogan: 致敬大師、致敬未來的你. * @create: 2020-07-16 10:17
*/ public class CountObjectSize { int a = 10; int b = 20; String[] aa =new String[]{"a","b","c"}; public static void main(String[] args) { Object object = new Object(); String s1 = ClassLayout.parseInstance(object).toPrintable(); System.out.println("空物件"+ s1); //空Object 開啟指標壓縮: markword 8bytes + class地址 4bytes + 成員變數 0bytes + 對齊填充 4bytes = 16bytes //空Object 關閉指標壓縮: markword 8bytes + class地址 8bytes + 成員變數 0bytes + 對齊填充 0bytes = 16bytes CountObjectSize countObjectSize = new CountObjectSize(); String s = ClassLayout.parseInstance(countObjectSize).toPrintable(); System.out.println(s); //非空Object 開啟指標壓縮: markword 8bytes + class地址 4bytes + 成員變數 4 + 4 + 4 bytes + 對齊填充 0bytes = 24bytes //非空Object 關閉指標壓縮: markword 8bytes + class地址 8bytes + 成員變數 4 + 4 + 8 bytes + 對齊填充 0bytes = 32bytes //陣列物件在關閉指標壓縮的情況下 8byte 開啟4byte //開啟指標壓縮,提升jvm執行效率 long l = GraphLayout.parseInstance(countObjectSize).totalSize(); System.out.println(l); } }

輸出:

1、空物件開啟/關閉指標壓縮:

空Object 開啟指標壓縮:  markword 8bytes + class指標 4bytes + 成員變數 0bytes + 對齊填充 4bytes = 16bytes

空Object 關閉指標壓縮:  markword 8bytes + class指標 8bytes + 成員變數 0bytes + 對齊填充 0bytes = 16bytes

2、包含陣列的物件開啟/關閉指標壓縮:


開啟指標壓縮:  markword 8bytes + class指標 4bytes + 成員變數 0bytes + 對齊填充 4bytes = 16bytes

關閉指標壓縮: markword 8bytes + class指標 8bytes + 成員變數 0bytes + 對齊填充 0bytes = 16bytes