JVM(九)指針壓縮原理-計算對象大小


前言:

Oop-Klass體系回顧,在JVM第一篇中講過了這部分內容,今天的內容也涉及,回顧一下。

ooPDesc

       ---------MarkOopDesc:存放鎖的信息,分代年齡等等

       ---------InstanceOopDesc:非數組對象

  ---------arrayOopDesc:數組對象

    -----typeArrayOopDesc:基本數據類型數組,對應的有個存放基本數據類型數組元信息的TypeArrayKlass。

    -----objArrayOopDesc:引用數據類型數組,對應有個objArrayKlass存放引用類型的元信息。

我們這里再舉個例子,通過HSDB查看在JVM中的對象。

 

 啟動HSDB,在jdk1.8/lib下執行:java -cp  sa-jdi.jar sun.jvm.hotspot.HSDB

  選擇main線程,打開stack memroy

第一個就是我們定義的Position對象的地址,第二個是字節數組,第三個是char數組。

 

我們Inspector查看Position對象。第一部分就是Oop,在對象里面有元數據類型的InstanceKlass。

這里有個重要的點就是:_layout_helper參數。

1:如果是非數組對象,這個大小指的就是類生成的對象的大小。

2:如果是數組對象,是個負值。

3:等於0的話,?

 

 內存布局

 我之前寫過一篇博客里面提到了這部分內容:https://blog.csdn.net/A7_A8_A9/article/details/105730007?spm=1001.2014.3001.5501

  

 

 

 

 補充:針對上面的內存布局,這里有幾點需要說明。

1:對象頭中類型指針-class pointer它是指向instanceklass在方法區的地址,如果開啟指針壓縮的情況下是占4B,如果不開啟是占8B。

2:如果對象不是數組,對象頭中的數組長度占0B。是數組的話占4字節,因此數組的長度最大為2的32次方-1.

3:實例數據中char類型數據在c++中是用short表示的,所以占兩個字節。

4:實例數據中的引用數據類型,如果開啟指針壓縮占4B,不開啟指針壓縮占8B。

計算對象大小

指針壓縮從jdk1.6之后是默認開啟的。可以通過參數控制。

-XX:+UseCompressedOops/-XX:-UseCompressedOops

可以引用:這個依賴來打印對象布局大小。

<dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.10</version>
        </dependency>

 

1:沒有實例數據的對象

測試代碼:

public class TestClass {
    public static void main(String[] args) {
        TestClass tes1= new TestClass();
        System.out.println(ClassLayout.parseInstance(tes1).toPrintable());
    }
}

結果:一共占16字節。

 

 我們算下,這個16是怎么來的。其實很簡單就是:對象頭8B+類型指針(壓縮)4B+數組長度0B+實例數據0B+4B(對齊填充)=16B

 不開啟指針壓縮就是:對象頭8B+類型指針(不開啟指針壓縮)8B+數組長度0B+實例數據0B=16B  沒有了對齊填充也是16B

2:有實例數據

我們給TestClass加兩個實例屬性。

public class TestClass {
    int i=2;
    String name="阿三";
    public static void main(String[] args) {
        TestClass tes1= new TestClass();
        System.out.println(ClassLayout.parseInstance(tes1).toPrintable());
    }
}

開啟指針壓縮:

Mark Word 8B+類型指針4B(壓縮)+數組長度0B+實例數據int 4B+引用數據類型4B(壓縮)+4B(對齊填充)=24B

我們看下運行結果:

關閉指針壓縮:

對象頭8B+類型指針8B(壓縮)+數組長度0B+實例數據int 4B+引用數據類型8B(壓縮)+4B(對齊填充)=32B

運行結果:

 

 指針壓縮

開啟指針壓縮是為了節省內存,尋址效率有些提高。

指針壓縮的原理:

假如分配的內存從0開始且順序存儲,三個對象分別: test1=16B  test2=24B  test3=32B, 三個地址分別:test1=00000, test2=16(十進制)  /10000(二進制),test3=40(十進制) 101000(二進制)。

我們都知道java中的對象都是8字節對齊的,8字節對齊有一個特點就是 1 000,發現了嗎 所有對象的指針后三位總是0。這就是指針壓縮的點。

壓縮原理就是兩句話:

1:存儲的時候,后三位抹除0.

      就變成:test1=00,test2=10

2:使用的時候,后三位補0.

它的指針不再表示對象在內存中的精確位置,而是表示 偏移量 。這意味着 32 位的指針可以引用 40 億個 對象 , 而不是 40 億個字節。最終, 也就是說堆內存增長到 32 GB 的物理內存,也可以用 32 位的指針表示。

使用HSDB查看指針壓縮現象:

示例代碼:

public class TestClass {
    public static void main(String[] args) {
        Position position = new Position(1, 2, 3);
        while(true);
    }
}

關閉指針壓縮:

 

 

 對象地址:

 

 打開指針壓縮:

 

對象大小明顯變小了,而且klass屬性也不一樣了。

這是因為在OopDesc中,指針壓縮和不壓縮klass存儲在不同的地方。

 

 

 

JVM調優基礎知識

1:上線前對JVM進行預估調優

2:上線后小規模調優

3:OOM,full GC 頻繁調優

主要調什么?

1:方法區

2:虛擬機棧

3:堆區

4:熱點代碼緩沖區

 


免責聲明!

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



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