打印已经声明并初始化了一个布尔变量的类的结果
res.LockTest0 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) 6b f0 fb 27 (01101011 11110000 11111011 00100111) (670822507) 12 1 boolean LockTest0.b false 13 3 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 3 bytes external = 3 bytes total打印一个不包含任何属性、方法的类的结果
res.LockTest1 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) 91 2c fc 27 (10010001 00101100 11111100 00100111) (670837905) 12 4 (loss due to the next object alignment) Instance size: 16 bytes Space losses: 0 bytes internal + 4 bytes external = 4 bytes total大小分析
在64位虚拟机下,对象在声明并初始化一个boolean变量的情况下是16 byte。 此时前12 byte是(object)对象头。然后有1个byte是 boolean类型的变量。还有3个byte是填充 通过输出的Space losses: 0 bytes internal + 3 bytes external = 3 bytes total也可以看出。因为64bit JVM要求一个对象的大小必须是8的整数位,在对象头已经占12byte的情况下,有4位是填充,在boolean型变量占一个byte的情况下,就会有3个byte填充。由此可见对齐数据并不是固定存在的,需要填充的时候才存在. 在64位虚拟机下,对象在不包含任何属性、方法的情况下也是16 byte。 此时前12 byte是(object)对象头。布局分析
置于顶部的是Java的对象头,它是实现synchronized的锁对象的基础,一般而言,synchronized使用的锁对象是存储在Java对象头里的。观察打印出来的图表,每一行都显示了4个字节,总共是12个字节.JVM使用两个字来存储对象头(如果对象是数组则会分配3个字,多出来的一个字记录的是数组长度),其主要结构是由Mark Word 和 kiass pointer(Class Metadata Address) 组成,其结构说明如下表。对象头分析,如下所示的对象头的二进制码,包含了各种信息:包括关于堆对象的布局、类型、GC状态、同步状态和标识哈希代码的基本信息。 注意: HashCode是地址,地址需要计算。HashCode需要计算得到,在内存中是不存在的。调用hashCode(),运行完后,在打印信息中的value区域的bit就会发生变化。 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) 91 2c fc 27 (10010001 00101100 11111100 00100111) (670837905)小结
如果对象头加实例数据的大小无法是8的倍数,则会产生对齐数据,所以java的对象组成不是固定的。因为只有对象头无法是8的倍数,所以没有实例数据就只有对象头和实例数据。 虚拟机位数头对象结构说明32/64bitMark Word存储对象的hashCode、锁信息或分代年龄或GC标志等信息32/64bitklass pointer类型指针指向对象的类元数据,JVM通过这个指针确定该对象是哪个类的实例。 Mark Word与klass pointer的大小 在32 bit JVM下Mark Word是32 bit 前25bit存的是hashCode在紧接着4个bit是GC分段年龄在紧接着1个bit是偏向锁的信息。在紧接着2个bit存的是同步状态 hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object) JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object) size:32 ----------------------------------------->|(CMS free block) PromotedObject*:29 --------->| promo_bits:3 ----->|(CMS promoted object) 在64 bit JVM下Mark Word的大小为64 bit 如果开启指针压缩,则klass pointer/Class Metadata Address是32 bit,此时对象头是96bit.不开启指针压缩的话klass pointer/Class Metadata Address是64 bit. unused:25 hash:31 -->| unused:1 age:4 biased_lock:1 lock:2(normal object) JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2(biased object) PromotedObject*:61 ------------------>| Promo_bits:3------>|(CMS promoted object) size:64 -------------------------------------------------->|(CMS free block)以上状态对应的 Mark Word内容通过打印可以观测到