对象在内存中存储的结构由三部分组成:对象头、实例数据、对齐填充。
对象头由三部分组成:
1、Mark Word:记录对象和锁的有关信息。当一个对象被synchronized关键字加锁之后,围绕锁的操作就都会和MarkWord有关联。MarkWord通常都是32bit位大小。会保存一些分代年龄、无锁状态下对象的HashCode、偏向锁的线程ID、轻量级锁指向栈中锁记录的指针、指向重量级锁的指针、锁的标志位等内容。
2、指向类的指针:大小也通常为32bit,它主要指向类的数据,也就是指向方法区中的位置。
3、数组长度:只有数组对象才有,在32位或者64位JVM中,长度都是32bit。
MarkWord是根据对象的状态区分不同的状态位,从而区分不同的存储结构。例如下图:
实例数据区:
实例数据部分是对象真正存储的有效信息,也就是我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的都需要记录下来。这部分的存储顺序会受到虚拟机分配策略参数(FieldsAllocationStyle)和字段在 Java源码中定义顺序的影响。
HotSpot虚拟机默认的分配策略为longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers),从分配策略中可以看出,相同宽度的字段总是被分配到一起。在满足这个前提条件的情况下,在父类中定义的变量会出现在子类之前。如果CompactFields参数值为true(默认为true),那子类之中较窄的变量也可能会插入到父类变量的空隙之中。
对齐填充:
第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于 HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是对象的大小必须是8字节的整数倍。对象头正好是8字节的倍数(1倍或者2倍),因此当对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。
Was this helpful?
0 / 0