Java锁升级的过程及对象头中的信息
一、先了解一下对象头是什么
HotSpot虚拟机的对象头(Object Header)包括两部分信息,第一部分用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等,这部分数据的长度在32位和64位的虚拟机中分别为32个和64个Bits,官方称它为“Mark Word”。本实例是基于jdk8,已经默认开启指针压缩。
Mark Word被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据对象的状态复用自己的存储空间。例如在32位的HotSpot虚拟机 中对象未被锁定的状态下,Mark Word的32个Bits空间中的25Bits用于存储对象哈希码(HashCode),4Bits用于存储对象分代年龄,2Bits用于存储锁标志 位,1Bit固定为0,在其他状态(轻量级锁定、重量级锁定、GC标记、可偏向)下对象的存储内容如下图所示。
对象头的前64位是MarkWord,后32位是类的元数据指针(开启指针压缩)。
二、利用jol打印对象头中的信息
public static void main(String[] args) {
Object object = new Object();
int hashCode = object.hashCode();
System.out.println("hash: " + hashCode);
System.out.println("0x" + Integer.toHexString(hashCode));
System.out.println(ClassLayout.parseInstance(object).toPrintable());
}
如下所示,画红线的部分是存储的hash值,“00000001”为分解为“0 0000 0 01”,“01”为锁标识位,“0”表示是否为偏向锁,“0000”表示分代年龄,最高位“0”未使用;从中可以看出当前为无锁状态。
hash: 1878246837
0x6ff3c5b5
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 b5 c5 f3 (00000001 10110101 11000101 11110011) (-205146879)
4 4 (object header) 6f 00 00 00 (01101111 00000000 00000000 00000000) (111)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
由于MarkWord其实是一个指针,在64位jvm下占8字节。因此MarkWordk是0x0000006ff3c5b5,跟你从图中看到的正好相反,这里涉及到一个知识点“大端存储与小端存储”,JVM里采用的小端存储(Little-Endian)。
Little-Endian:低位字节存放在内存的低地址端,高位字节存放在内存的高地址端。
Big-Endian:高位字节存放在内存的低地址端,低位字节存放在内存的高地址端。
执行如下代码:
synchronized (object){
System.out.println("locking:");
System.out.println(ClassLayout.parseInstance(object).toPrintable());
}
输出:
locking:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 70 f8 47 03 (01110000 11111000 01000111 00000011) (55048304)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
“011100 00”中后2位是“00”,此时是轻量级锁,那么前面62位就是指向栈中锁记录的指针。“00000000 00000000 00000000 00000000 00000011 01000111 11111000 011100”。