Java里面一个对象到底占用多少空间

Java里面一个对象到底有占用多少空间,这个问题要分情况看,我们先来看Java里面最顶层的Object类,它里面只有方法,没有成员变量,也就是说通过new一个Object对象就可以知道一个Java对象最少要占用多少空间,我们通过引入jol工具来打印出对象布局:

首先添加pom依赖:

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

我们先看Object:

public class JolMain {
    public static void main(String[] args) {
        Object obj = new Object();
        String layout = ClassLayout.parseInstance(obj).toPrintable();
        System.out.println(layout);
    }
}

输出信息如下:

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 20 (11100101 00000001 00000000 00100000) (536871397)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

看不懂没关系,但是我们注意到这么几个关键的信息

12     4        (loss due to the next object alignment)

Instance size: 16 bytes

Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

可以看到一个Object对象占用16个字节,其中有4个字节是不属于这个对象本身的内容,是额外填充的,至于为什么要填充,Java中的对象对齐是为了提高内存访问的效率。根据Java虚拟机规范,对象的起始地址必须是某个特定大小的倍数,通常是8字节或者更大的2的幂次方。这样做的目的是为了确保对象的字段可以按照自然对齐的方式存储,以提高内存访问的效率,我们在启动参数里加一个参数:-XX:-UseCompressedOops,同样是上面的代码,输出的结果如下:

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           00 1c d3 17 (00000000 00011100 11010011 00010111) (399711232)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

可以看到这个时候就没有额外填充4个字节了,这个UseCompressedOops意思是时否开启压缩指针,因为在java对象头里面有一个类型指针指向它所属的类型,默认情况下是开启的,这个类型指针占4个字节,那么一个默认情况下Object对象实际上只占用了12个字节,为了对齐,额外填充了4个字节,而当我们不开启指针压缩的时候,类型指针站8个字节,这个时候就不需要对齐填充了

那么在默认情况下怎么保证不进行填充呢,我们新建一个User类试试:

public class User {
    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public static void main(String[] args) {
        User user = new User();
        String layout = ClassLayout.parseInstance(user).toPrintable();
        System.out.println(layout);
    }
}

我们看输出结果:没有填充

org.example.jol.User object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           54 c3 00 20 (01010100 11000011 00000000 00100000) (536920916)
     12     4    int User.id                                   0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

我们在user里面继续加一个long类型字段(8个字节):

public class User {
    private int id;
    private long age;

    public long getAge() {
        return age;
    }

    public void setAge(long age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public static void main(String[] args) {
        User user = new User();
        String layout = ClassLayout.parseInstance(user).toPrintable();
        System.out.println(layout);
    }
}

输出结果:没有填充

org.example.jol.User object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           54 c3 00 20 (01010100 11000011 00000000 00100000) (536920916)
     12     4    int User.id                                   0
     16     8   long User.age                                  0
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

继续加一个int类型字段(4个字节):

public class User {
    private int id;
    private long age;
    private int uid;

    public int getUid() {
        return uid;
    }

    public void setUid(int uid) {
        this.uid = uid;
    }

    public long getAge() {
        return age;
    }

    public void setAge(long age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public static void main(String[] args) {
        User user = new User();
        String layout = ClassLayout.parseInstance(user).toPrintable();
        System.out.println(layout);
    }
}

输出结果:有填充

org.example.jol.User object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           54 c3 00 20 (01010100 11000011 00000000 00100000) (536920916)
     12     4    int User.id                                   0
     16     8   long User.age                                  0
     24     4    int User.uid                                  0
     28     4        (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

由此可以看到,一个java对象占用的空间是8个字节的倍数,如果实际占用空间不满足这个条件的话,就会进行填充对齐

结论:

1、Java里面一个对象最少占用16个字节

2、默认情况下,jvm开启了指针压缩,对象头中的类型指针占用4个字节,关闭指针压缩就会占用8个字节

3、java对象占用空间一般是8字节的倍数,如果不满足的话,会自动填充以达到这个对齐的目的

猜你喜欢

转载自blog.csdn.net/qq_17805707/article/details/132356293