金三银四面试题(六):对象大小知多少

发布于:2024-03-29 ⋅ 阅读:(63) ⋅ 点赞:(0)

对象和数组在JVM如何在堆中布局?更常见地问法就是对象头都包含哪些信息

在JVM中对象和数组尽管都是连续的内存块。但在堆内存中的布局方式有些不同。

对象的组成

对象在JVM中可以分为三个部分,对象头(Header),实例数据(Instance Data)和对其填充(Padding)

那么在对象头中,有两个最重要地部分

  • mark word,HotSpot JVM 使用mark word来存储身份哈希码、偏向锁定模式、锁定信息和 GC 元数据。

详情可以参考https://gist.github.com/arturmkrtchyan/43d6135e8a15798cc46c

  • klass 类型指针,封装了类地元信息,例如类名、其修饰符、父类类信息等。其大小在 32 位和 64 位架构中分别为 4 和 8 字节。 此外,有偏向锁的对象和正常对象的标记词是不同的。但是,这里我们只会考虑普通对象,因为从 Java 15 默认关闭偏向锁。

对象的大小

对于 Java 中表示为instanceOop的普通对象,对象头由 mark 和 klass 字以及可能的对齐 padding 组成。在对象头之后,可能有零个或多个对实例字段的引用。因此,在 64 位架构中至少有 16 个字节(8个字节的标记、4个字节的klass和另外4个字节的padding填充)。

面试中有个最基本的问题,Object o = new Object();o的大小是多少?

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

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)                           08 0d 00 00 (00001000 00001101 00000000 00000000) (3336)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

对于表示为 arrayOop 的数组, 对象头除了 mark、klass 和 paddings 之外还包含 4 字节数组长度。所以最少是 16 个字节(8 个字节的标记、4个字节的klass和另外4个字节的数组长度。

如果面试题换做new int[0]的大小是多少?

public static void main(String[] args) {
    System.out.println(ClassLayout.parseInstance(new int[0]).toPrintable());
}

[I 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)                           68 22 00 00 (01101000 00100010 00000000 00000000) (8808)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     16     0    int [I.<elements>                             N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

如果将数组长度扩大到10

[I 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)                           68 22 00 00 (01101000 00100010 00000000 00000000) (8808)
     12     4        (object header)                           0a 00 00 00 (00001010 00000000 00000000 00000000) (10)
     16    40    int [I.<elements>                             N/A
Instance size: 56 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

压缩引用

我们可以使用 jvm参数 -XX:-UseCompressedOops 禁用指针压缩,那么 klass 字将消耗 8 个字节而不是 4 个字节。

总结

Java对象的内存布局也算是面试中的高频题,强烈建议学习JVM源代码特别是oops部分。参考资料

往期文章

金三银四面试题(一):JVM类加载与垃圾回收

金三银四面试题(二):数据库缓存的数据一致性

金三银四面试题(三):JVM内存模型

金三银四面试题(四):Full GC 和 Minor GC

金三银四面试题(五):JVM之TLAB

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到