Как интерпретировать слово метки экземпляра?
Я пытаюсь понять вывод макета объекта Java на 64-битной виртуальной машине HotSpot (v8). Я не понимаю, как используются первые три бита слова метки, которые в соответствии с комментарием в связанном файле класса должны указывать, установлена ли на экземпляр смещенная блокировка или не смещенная блокировка.
Когда я анализирую случай Object
используя JOL
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 (первые 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
- Эпоха бит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 знает, что это предвзятая блокировка, а не хеш-код, представленный в объекте. Я также задаюсь вопросом: что означают биты эпохи?
1 ответ
Ответ прост: комментарии OpenJDK устарели, а слово "пометка" организовано по-другому.