Как интерпретировать слово метки экземпляра?

Я пытаюсь понять вывод макета объекта 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 устарели, а слово "пометка" организовано по-другому.

Другие вопросы по тегам