在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
