1. 程式人生 > >java物件記憶體佈局中的基本型別欄位排列順序

java物件記憶體佈局中的基本型別欄位排列順序

java物件記憶體佈局:

  1. mark word

  2. class物件指標

  3. 類欄位
  4. 補齊位

如果是陣列物件,2、3之間應該加上  陣列長度

佈局排列表:

32位jdk 普通物件

32位jdk 陣列物件

64位jdk 未開啟指標壓縮 普通物件

64位jdk 未開啟指標壓縮 陣列物件

64位jdk 開啟指標壓縮 普通物件

64位jdk 開啟指標壓縮 陣列物件

Mark word(m)

4

4

8

8

8

8

class指標(c)

4

4

8

8

4

4

陣列長度(l)

0

4

0

8

0

4

類欄位(f)

補齊位(p)

單位(byte).   總計 (m+c+l+f+p) % 8 = 0

類欄位排列

本文主要簡述一下類欄位的排列規則。

java物件所佔記憶體大小強制8位元組對齊,因此補齊位的存在就是為了補齊8位元組,每一個java物件的大小都是8的倍數。(注:本文所說的物件皆為Shallow size,不包含引用物件的大小)

UnSafe

通過 sun.misc.UnSafe#objectFieldOffset(Field) 來獲取欄位在記憶體中的偏移量

final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
final Unsafe unsafe = (Unsafe) theUnsafe.get(null);

規則一:(m+c+l) %8 =0

類欄位排列規則按照先基本型別,後引用型別,大的在前,小的在後,最後按宣告順序排列。對齊以四位元組為單位。下為樣例程式碼:

//以64位jdk 未開啟指標壓縮 普通物件為例
public class Demo {
    //32
    private String str;

    //16
    private long l;

    //24
    private int i;

    //30
    private byte b;

    //28
    private short s;

   


    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        final Unsafe unsafe = (Unsafe) theUnsafe.get(null);

        
 System.out.println(unsafe.objectFieldOffset(Demo.class.getDeclaredField("l")));
        System.out.println(unsafe.objectFieldOffset(Demo.class.getDeclaredField("i")));
        System.out.println(unsafe.objectFieldOffset(Demo.class.getDeclaredField("b")));
        System.out.println(unsafe.objectFieldOffset(Demo.class.getDeclaredField("s")));
        System.out.println(unsafe.objectFieldOffset(Demo.class.getDeclaredField("str")));

    }

}

規則二:(m+c+l) % 8 !=0

優先從基本型別欄位中找出一個 欄位f,使得 (m+c+l+f) %8 =0,如64位jdk開啟指標壓縮的普通物件mark word+class refence = 12,如果類欄位中有int或者float,會優先把這個欄位排在前面 ,如果有多個的話,只會選擇排在最前列的那個欄位,其餘欄位按照規則一排列;如果沒有int或者float,會根據大小的順序選擇 short char byte boolean,選擇一個或多個欄位大小和為4byte排列,如果只有一個上述欄位,那就只排列一個,然後補空位到4byte。

下為樣例程式碼一:

//以64位jdk 開啟指標壓縮 普通物件為例
public class Demo2 {

    //16
    private long l;

    //12
    private int i;

    //24
    private String str;


    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        final Unsafe unsafe = (Unsafe) theUnsafe.get(null);


        System.out.println(unsafe.objectFieldOffset(Demo2.class.getDeclaredField("l")));
        System.out.println(unsafe.objectFieldOffset(Demo2.class.getDeclaredField("i")));
        System.out.println(unsafe.objectFieldOffset(Demo2.class.getDeclaredField("str")));

    }

}

樣例程式碼二:

//以64位jdk 開啟指標壓縮 普通物件為例
public class Demo2 {

    //16
    private long l;

    //14
    private byte b;

    //12
    private short s;

    //24
    private String str;


    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafe.setAccessible(true);
        final Unsafe unsafe = (Unsafe) theUnsafe.get(null);


        System.out.println(unsafe.objectFieldOffset(Demo2.class.getDeclaredField("l")));
        System.out.println(unsafe.objectFieldOffset(Demo2.class.getDeclaredField("b")));
        System.out.println(unsafe.objectFieldOffset(Demo2.class.getDeclaredField("s")));
        System.out.println(unsafe.objectFieldOffset(Demo2.class.getDeclaredField("str")));

    }

}

規則三:繼承關係

按照規則一和規則二先排列父類欄位,再排列子類欄位,父類欄位加上mark word + class reference 也會八位元組對齊