天天看點

深入了解JVM虛拟機——Java對象記憶體布局

作者:一個即将被退役的碼農

Java對象的記憶體布局

一個Java對象在記憶體中包括三部分

  1. 對象頭
  2. 執行個體資料
  3. 補齊填充
深入了解JVM虛拟機——Java對象記憶體布局

在這裡插入圖檔描述

對象頭

對象頭又分為以下三部分

  • Mark Word:Mark Word存儲了對象的hashCode、GC資訊、鎖資訊三部分。在32位系統占4位元組,在64位系統中占8位元組;
  • Class Pointer:用來指向對象對應的Class對象(其對應的中繼資料對象)的記憶體位址。在32位系統占4位元組,在64位系統中占8位元組,如果64位開啟了指針壓縮則4位元組。
  • Length:如果是數組對象,還有一個儲存數組長度的空間,占4個位元組;

對象頭記憶體分布圖

深入了解JVM虛拟機——Java對象記憶體布局

在這裡插入圖檔描述

對象實際資料

對象實際資料包括了對象的所有成員變量,其大小由各個成員變量的大小決定,,比如:byte和boolean是1個位元組,short和char是2個位元組,int和float是4個位元組,long和double是8個位元組,reference是4個位元組(64位系統中是8個位元組)。

深入了解JVM虛拟機——Java對象記憶體布局

對齊填充

Java對象占用空間是8位元組對齊的,即所有Java對象占用bytes數必須是8的倍數。例如,一個包含兩個屬性的對象:int和byte,這個對象需要占用8+4+1=13個位元組,這時就需要加上大小為3位元組的padding進行8位元組對齊,最終占用大小為16個位元組。

如何列印Java對象記憶體布局

<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>           
public class TestMemory {
    public static void main(String[] args) {
        System.out.println(VM.current().details());
        System.out.println(ClassLayout.parseClass(A.class).toPrintable());
    }
}

class A{
    long i;
}           
深入了解JVM虛拟機——Java對象記憶體布局

練習

以下均指預設開啟指針壓縮的情況

一、static變量不占用空間

public class A{
    int a;
    long b;
    static int c;
}

public class TestMemory {

    public static void main(String[] args) {
        A a = new A();
        System.out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}           
深入了解JVM虛拟機——Java對象記憶體布局

二、不滿8的倍數填充位元組

public class TestObjectSize {
    int a;
    int b;
}           
深入了解JVM虛拟機——Java對象記憶體布局

三、引用占4個位元組

public class A {
    Long[] a=new Long[]{1L,2L,3L};

    public Long[] getA() {
        return a;
    }

    public void setA(Long[] a) {
        this.a = a;
    }
}           
深入了解JVM虛拟機——Java對象記憶體布局

四、數組對象長度占4個位元組,有長度的數組按數組長度算占用位元組

public class A {
    Long[] a=new Long[10];

    public Long[] getA() {
        return a;
    }

    public void setA(Long[] a) {
        this.a = a;
    }
}

public class TestMemory {

    public static void main(String[] args) {
        A a = new A();
        System.out.println(ClassLayout.parseInstance(a.getA()).toPrintable());
    }
}           
深入了解JVM虛拟機——Java對象記憶體布局

繼續閱讀