我试图理解64位HotSpot VM(v8)上Java object layout的输出。我不明白如何使用first three bit of the mark word根据链接类文件中的注释应该指示天气在实例上设置偏置锁或非偏置锁。
当我使用JOL
分析Object
的实例时
ClassLayout layout = ClassLayout.parseClass(Object.class);
Object object = new Object();
System.out.println(layout.toPrintable(object));
我得到以下输出:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (0000 0001 0000 0000 0000 0000 0000 0000)
4 4 (object header) 00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000)
8 4 (object header) e5 01 00 f8 (1110 0101 0000 0001 0000 0000 1111 1000)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes (estimated, add this JAR via -javaagent: to get accurate result)
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
从HotSpot's description of the mark word(前8个字节),我理解我应该解释输出的上述位范围如下:
00:01
- 锁定标志(示例中为00
。)02:02
- 有偏见的锁定标志(例如0
。)03:06
- 作为年轻垃圾收集迭代次数的年龄。 (例如0000
。)07:07
- 未使用。 (似乎总是1
。)08:39
- 身份哈希码。 (仅在计算之后,才填充零。)40:63
- 未使用。 (似乎是用零填充。)确认哈希码范围的此布局
至少对于哈希码,可以通过计算身份哈希码并比较值来轻松确认:
ClassLayout layout = ClassLayout.parseClass(Object.class);
Object object = new Object();
// Check that the hash code is not set.
System.out.println(layout.toPrintable(object));
System.out.println("hash code: 0x" + Integer.toHexString(object.hashCode()));
// Confirm that the value is set:
System.out.println(layout.toPrintable(object));
// Compute the hash code manually:
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
long hashCode = 0;
for (long index = 7; index > 0; index--) {
hashCode |= (unsafe.getByte(object, index) & 0xFF) << ((index - 1) * 8);
}
System.out.println("hash code: 0x" + Long.toHexString(hashCode));
其中哈希码被设置为实际位(忽略它仅由31位而不是32表示,因为提醒被设置为零)。锁的标志都按预期设置为零。
验证偏向锁定的布局
markOops 还给出了对象何时受到偏向锁定的布局。在这里,最后两个项目符号点将替换为以下范围:
08:09
- Epoch bit 10:63
- 持有此偏置锁的线程的指针。当我现在尝试使用-XX:BiasedLockingStartupDelay=0
运行以下代码的偏置锁时,我还可以观察如何设置偏置锁。当我运行以下代码时:
ClassLayout layout = ClassLayout.parseClass(Object.class);
Object object = new Object();
// Before using any lock, the layout is as above.
System.out.println(layout.toPrintable(object));
// When acquiring the lock, the thread ID can be seen as below:
synchronized (object) {
System.out.println(layout.toPrintable(object));
}
// After leaving the lock, the object is biased towards this thread:
System.out.println(layout.toPrintable(object));
在初始锁定后的标记字中可以看到偏置锁定,如下所示:
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 f0 3f 02 (0000 0101 1111 0000 0011 1111 0000 0010)
4 4 (object header) 00 00 00 00 (0000 0000 0000 0000 0000 0000 0000 0000)
8 4 (object header) e5 01 00 f8 (1110 0101 0000 0001 0000 0000 1111 1000)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes (estimated, add this JAR via -javaagent: to get accurate result)
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
一旦我调用object.hashCode()
,我就可以验证这不代表哈希码,因为标记词会改变(偏向锁被撤销)。
我不明白的是,偏置锁定和非偏置锁定的标志仍然设置为零。 HotSpot如何知道这是一个有偏见的锁,而不是对象中表示的哈希码。我还想知道: epoch 位表示什么?
答案 0 :(得分:1)
答案很简单:OpenJDK的评论已经过时,而且今天标记词的组织方式也不同。