代码主要通过打印对象的内存布局来观察对象头在不同状态下的变化,进而分析对象头在不同情况下的内存布局情况。
-
System.out.println(ClassLayout.parseInstance(o).toPrintable());
:这一行代码通过使用开源库openjdk.jol
的ClassLayout
类来解析对象o
的内存布局,并将其打印出来。初始时,对象o
是一个普通的Object
对象,还没有被锁定。 -
int hashCode = o.hashCode();
:这一行代码调用了对象o
的hashCode
方法,生成了哈希码并赋值给hashCode
变量。 -
System.out.println(Integer.toBinaryString(hashCode));
:这一行代码将生成的哈希码转换为二进制字符串并打印出来。 -
System.out.println(ClassLayout.parseInstance(o).toPrintable());
:这一行代码再次打印对象o
的内存布局,此时对象o
的哈希码已经生成,但对象仍处于未锁定状态。 -
synchronized (o) { System.out.println(ClassLayout.parseInstance(o).toPrintable()); }
:这一段代码使用 synchronized 块对对象o
进行加锁,并打印加锁后对象o
的内存布局。
根据代码执行的过程和结果,可以得出以下分析:
- 初始时,对象
o
是一个普通的Object
对象,其内存布局包括对象头、实例数据和对齐填充。 - 在调用
hashCode
方法后,对象o
的哈希码生成并存储在对象头的标记字中,此时对象头的内容发生了变化。 - 在加锁之前和加锁之后,对象头的锁状态也会发生变化,加锁后会生成锁记录并存储在对象头中,从而导致对象头的内容再次发生变化。
通过观察对象头在不同状态下的变化,可以更加深入地理解 Java 对象在内存中的布局和状态管理机制。
public static void main(String[] args) {
Object o = new Object();
System.out.println("======原始对象布局======");
System.out.println(ClassLayout.parseInstance(o).toPrintable());
int hashCode = o.hashCode();
System.out.println(Integer.toBinaryString(hashCode));
System.out.println("======调用对象hashCode后======");
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o) {
System.out.println("======加锁中======");
System.out.println(ClassLayout.parseInstance(o).toPrintable());
System.out.println("======加锁中======");
}
System.out.println("======释放锁后======");
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
加锁中时,对象头hashCode去哪了
参考:
当Java处在偏向锁、重量级锁状态时,hashcode值存储在哪? - 知乎