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

 

 

 

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM