本文的主要问题如下:

问题:new Object() 在内存中占用多少字节?

对象的结构

Hotspot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

  • 对象头:比如 hash 码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象才有)等。
  • 实例数据:存放类的属性数据信息,包括父类的属性信息;
  • 对齐填充:由于虚拟机要求 对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐。

直观一点:
如何计算一个对象的大小? - 图1

对象头详解

HotSpot虚拟机的对象头包括:

  • Mark Word

用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机中分别为 32bit 和 64bit,官方称它为 “Mark Word”。 也就是说32位虚拟机4字节,64位虚拟机8字节。
Mark Word 中具体存的是什么呢?我们可以看下面这一张表(以 64 位操作系统为例,这里暂不展开):
如何计算一个对象的大小? - 图2

  • Klass Pointer

对象头的另外一部分是klass类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。 32位4字节,64位开启指针压缩或最大堆内存<32g时4字节,否则8字节。jdk1.8默认开启指针压缩后为4字节,当在JVM参数中关闭指针压缩(-XX:-UseCompressedOops)后,长度为8字节。

  • 数组长度(只有数组对象有)

如果对象是一个数组, 那在对象头中还必须有一块数据用于记录数组长度。 长度为4字节。
如何计算一个对象的大小? - 图3

正确答案

在 JDK8 下 64位操作系统中 new Object() 占多少字节?
答案:16 字节
8 个字节是 MarkWord
4 个字节是指针(jdk 8 默认开启指针压缩) 4 个字节是对齐填充位

动手实践一下

  1. jol 插件可以打印对象布局,首先我们加入依赖:

    1. implementation 'org.openjdk.jol:jol-core:0.9'
  2. 测试代码 ```java public class NewObjectLayoutTest {

    public static void main(String[] args) {

    1. System.out.println(ClassLayout.parseInstance(new Object()).toPrintable());

    } }

  1. 1. 输出结果
  2. ```java
  3. java.lang.Object object internals:
  4. OFFSET SIZE TYPE DESCRIPTION VALUE
  5. 0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
  6. 4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
  7. 8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
  8. 12 4 (loss due to the next object alignment)
  9. Instance size: 16 bytes
  10. Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

总结

大家 get 到了吗?理论是实践的基础,欢迎留言。

参考


作者:心城以北
链接:https://juejin.cn/post/7101658548232257549
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。