«1. Обзор
В этом кратком руководстве мы увидим, как найти адрес памяти объектов в Java.
Прежде чем идти дальше, стоит упомянуть, что расположение областей данных времени выполнения в памяти не является частью спецификации JVM и остается на усмотрение разработчика. Поэтому у каждой реализации JVM может быть своя стратегия размещения объектов и массивов в памяти. Это, в свою очередь, повлияет на адреса памяти.
В этом руководстве мы сосредоточимся на одной конкретной реализации JVM: HotSpot JVM. Мы также можем использовать термины JVM и HotSpot JVM как синонимы на протяжении всего руководства.
2. Зависимость
Чтобы найти адрес памяти объектов в JVM, мы собираемся использовать инструмент Java Object Layout (JOL). Поэтому нам нужно добавить зависимость jol-core:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
3. Адрес памяти
Чтобы найти адрес памяти конкретного объекта в JVM, мы можем использовать метод addressOf():
String answer = "42";
System.out.println("The memory address is " + VM.current().addressOf(answer));
Это напечатает:
The memory address is 31864981224
В HotSpot JVM есть разные сжатые эталонные режимы. Из-за этих режимов это значение может быть неточным. Следовательно, мы не должны выполнять какие-либо манипуляции с собственной памятью на основе этого адреса, так как это может привести к странным повреждениям памяти.
Кроме того, адреса памяти в большинстве реализаций JVM могут изменяться, поскольку GC время от времени перемещает объекты.
4. Хэш-код идентификации
Существует распространенное заблуждение, что адреса памяти объектов в JVM представлены как часть их реализаций toString по умолчанию, таких как [email protected]. То есть многие думают, что «60addb54» — это адрес памяти этого конкретного объекта.
Давайте проверим это предположение:
Object obj = new Object();
System.out.println("Memory address: " + VM.current().addressOf(obj));
System.out.println("toString: " + obj);
System.out.println("hashCode: " + obj.hashCode());
System.out.println("hashCode: " + System.identityHashCode(obj));
Это напечатает следующее:
Memory address: 31879960584
toString: [email protected]
hashCode: 1622006612
hashCode: 1622006612
Довольно интересно, что «60addb54» — это шестнадцатеричная версия хеш-кода, то есть 1622006612. hashCode( ) является одним из общих методов для всех объектов Java. Если мы не объявляем метод hashCode() для класса, Java будет использовать для него идентификационный хэш-код.
Как показано выше, идентификационный хэш-код (часть после @ в toString) и адрес памяти отличаются.
5. Заключение
В этом коротком руководстве мы увидели, как найти адрес памяти объектов в Java.
Как обычно, все примеры доступны на GitHub.