java对象内存布局中的基本类型字段排列顺序

java对象内存布局:

  1. mark word(记录hashCode值和锁的标识等等)

  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 也会八字节对齐

你可能感兴趣的:(java)