JVM は System.identityHashCode() が変更されないことをどのようにして保証するのでしょうか?
-
21-08-2019 - |
質問
通常、デフォルトの実装は Object.hashCode()
メモリ内のオブジェクトに割り当てられたアドレスの関数です (ただし、これは、 JLS)。VM がメモリ内でオブジェクトをシャントするとすると、なぜ返される値は System.identityHashCode()
オブジェクトの存続期間中は決して変更されないのでしょうか?
「ワンショット」計算の場合 (オブジェクトの hashCode
は一度計算され、オブジェクトヘッダーか何かに隠されます)、それは、2つのオブジェクトが同じものを持つ可能性があることを意味しますか? identityHashCode
(最初にメモリ内の同じアドレスに割り当てられた場合)?
解決
最新の JVM は値をオブジェクト ヘッダーに保存します。通常、オブジェクトの割り当てに費やす時間を最小限に抑えるために (場合によっては 12 サイクル程度まで)、この値は最初の使用時にのみ計算されると思います。共通の Sun JVM は、すべてのオブジェクトの ID ハッシュ コードが常に 1 になるようにコンパイルできます。
複数のオブジェクトが同じ ID ハッシュ コードを持つことができます。それがハッシュコードの性質です。
他のヒント
2 番目の質問に対する答えとしては、実装に関係なく、複数のオブジェクトが同じidentityHashCodeを持つ可能性があります。
見る バグ 6321873 javadoc の文言に関する簡単な説明と、非一意性を示すプログラムについて説明します。
HotSpot のオブジェクトのヘッダーは、クラス ポインターと「マーク」ワードで構成されます。
マークワードのデータ構造のソースコードは、次の場所にあります。 markOop.hpp
ファイル。このファイルには、マーク ワードのメモリ レイアウトを説明するコメントがあります。
hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)
ここでは、32 ビット システム上の通常の Java オブジェクトの ID ハッシュ コードがマーク ワードに保存され、長さが 25 ビットであることがわかります。
ハッシュ関数を実装するための一般的なガイドラインは次のとおりです。
- 同じオブジェクトは一貫した hashCode を返す必要があります, 、時間の経過とともに変化したり、変数情報に依存したりしてはなりません(例:乱数または変更可能なメンバーフィールドの値によってシードされるアルゴリズム
- ハッシュ関数には 良いランダム分布, つまり、ハッシュコードをバケットとして考える場合、2 つのオブジェクトは可能な限り異なるバケット (ハッシュコード) にマッピングする必要があります。2 つのオブジェクトが同じハッシュコードを持つ可能性はほとんどありませんが、 できる 起こる。
私の知る限り、これはオブジェクトの存続期間中決して変更されない参照を返すために実装されています。