1. 概要

このクイックチュートリアルでは、Javaでオブジェクトのメモリアドレスを見つける方法を見ていきます。

先に進む前に、ランタイムデータ領域のメモリレイアウトはJVM仕様の一部ではなく、実装者裁量に任されていることに言及する価値があります。 したがって、各JVM実装には、メモリ内のオブジェクトと配列をレイアウトするための異なる戦略がある場合があります。 これは、メモリアドレスに影響を及ぼします。

このチュートリアルでは、特定のJVM実装であるHotSpotJVMに焦点を当てています。 また、チュートリアル全体で、JVMとHotSpotJVMの用語を同じ意味で使用する場合があります。

2. 依存

JVM内のオブジェクトのメモリアドレスを見つけるには、Javaオブジェクトレイアウト( 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内のオブジェクトのメモリアドレスは、 java .lang.Object @60addb54などのデフォルトのtoString実装の一部として表されるという一般的な誤解があります。 つまり、多くの人は、「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: java.lang.Object@60addb54
hashCode: 1622006612
hashCode: 1622006612

非常に興味深いことに、「60addb54」は、ハッシュコードの16進バージョンである1622006612です。 hashCode()メソッドは、すべてのJavaオブジェクトに共通のメソッドの1つです。 hashCode()を宣言しない場合クラスのメソッドであるJavaは、そのクラスのIDハッシュコードを使用します。 

上記のように、 IDハッシュコードtoString@の後の部分)とメモリアドレスが異なります

5. 結論

この短いチュートリアルでは、Javaでオブジェクトのメモリアドレスを見つける方法を見ました。

いつものように、すべての例はGitHubから入手できます。