2009-06-30 25 views
62

In genere l'implementazione predefinita di Object.hashCode() è una funzione dell'ubicazione assegnata dell'oggetto in memoria (sebbene ciò non sia richiesto dallo JLS). Dato che la VM smuove gli oggetti in memoria, perché il valore restituito da System.identityHashCode() non cambia mai durante la vita dell'oggetto?In che modo JVM garantisce che System.identityHashCode() non cambierà mai?

Se si tratta di un calcolo "one-shot" (dell'oggetto hashCode viene calcolato una volta e nascosto nell'intestazione oggetto o qualcosa del genere), allora vuol dire che è possibile per due oggetti hanno la stessa identityHashCode (se capita essere prima assegnato allo stesso indirizzo in memoria)?

+1

Domanda correlata: la memoria è indirizzata a un indirizzo di memoria reale oa qualcosa di virtuale che può rimanere fisso anche quando l'oggetto viene mescolato?Se virtuale, sarebbe bello perché i puntatori a questo non avrebbero bisogno di essere regolati. D'altra parte, ciò significherebbe un'ulteriore indiretta e una tabella di mappatura potenzialmente grande. – Thilo

+3

È un leggero riarrangiamento dell'indirizzo quando richiesto per la prima volta. (Il ritorno di un codice hash con bit bassi a zero non è eccezionale.) –

+0

In realtà, dove dice che identityHashCode non deve mai cambiare? JavaDoc per System.identityHashCode non è chiaro su questo. – Thilo

risposta

35

Le JVM moderne salvano il valore nell'intestazione dell'oggetto. Credo che il valore sia tipicamente calcolato solo al primo utilizzo al fine di mantenere il tempo trascorso nell'assegnazione degli oggetti al minimo (a volte fino a una dozzina di cicli). La comune Sun JVM può essere compilata in modo che il codice hash dell'identità sia sempre 1 per tutti gli oggetti.

Più oggetti possono avere lo stesso codice di identità. Questa è la natura dei codici hash.

+3

Destra: ho appena guardato ObjectSynchronizer :: FastHashCode in synchronizer.cpp (codice sorgente runtime di vm) e dopo aver generato l'hashcode, sembra che si unisca all'intestazione dell'oggetto. Sembra che ci siano diverse possibili implementazioni di HashCode; quello che alludi a quello restituisce 1 per tutti gli oggetti viene utilizzato per garantire che nessuna parte della VM presuma che gli hashcode siano univoci per qualsiasi motivo. – butterchicken

+0

public static native ident identHashCode (Object x); è un metodo nativo. Sei in grado di spiegarlo dal punto di vista del codice implementato nativo? Intendo C++ implementation.it è usato principalmente in inentibilityHashMap? –

+0

@ Tom Cosa intendi per intestazione dell'oggetto? Hai anche scritto "Credo che il valore sia tipicamente calcolato solo al primo utilizzo al fine di mantenere l'allocazione degli oggetti al minimo (a volte fino a una dozzina di cicli)." Puoi spiegare a quale oggetto si riferisce qui? – Geek

-3

Per quanto ne so, questo è implementato per restituire il riferimento, che non cambierà mai nella vita di un oggetto.

+0

Quindi stai dicendo che il riferimento non è un vero indirizzo di memoria (o direttamente derivato da quello). Quindi è una sorta di puntatore al vero indirizzo di memoria? – Thilo

15

In risposta alla seconda domanda, indipendentemente dall'implementazione, è possibile che più oggetti abbiano la stessa identitàHashCode.

Vedere bug 6321873 per una breve discussione sulla dicitura in javadoc e un programma per dimostrare la non unicità.

+1

Vero. Due oggetti diversi possono avere lo stesso hashCode. Questo è il caso con tutte le funzioni hash (su un dominio più grande della loro dimensione del risultato). – Thilo

+2

Si tratta di un bug report molto buono. :) –

+1

@Thilo: La JVM avrebbe potuto essere scritta in modo tale da garantire che, purché non esistano mai più di quattro miliardi di oggetti in una volta, 'identityHashCode' non restituirebbe mai un valore che era stato restituito con nessun altro oggetto che è ancora esistente. A seconda di come viene implementato il gestore della memoria, questo potrebbe essere costoso, o potrebbe aggiungere zero costi aggiuntivi. Ad esempio, un 'Object' potrebbe contenere un indice in una tabella di puntatori, assegnando a ogni oggetto uno spazio di tabella immutabilmente fino a quando esiste. Le implementazioni tipiche di JVM non lo fanno ... – supercat

0

L'orientamento generale per l'attuazione di una funzione di hashing è:

  • stesso oggetto deve restituire un hashCode coerente, non dovrebbe cambiare con il tempo o dipendono informazioni variabili (ad esempio un algoritmo seminato da un numero casuale o valori di campi membri mutabili
  • la funzione hash dovrebbe avere una distribuzione casuale buona , e con questo intendo se si considera l'hashcode come bucket, 2 oggetti dovrebbero mappare su diversi bucket (hashcode) il più lontano possibile . La possibilità che 2 oggetti dovrebbe avere lo stesso hashcode dovrebbe essere raro - anche se può accadere.
0

L'intestazione di un oggetto in HotSpot è costituita da un puntatore di classe e una parola di "marchio".

Il codice sorgente della struttura dati per la parola contrassegno può essere trovato nel file markOop.hpp. Nel file è un commento che descrive il layout della memoria del marchio denominativo:

hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object)

Qui possiamo vedere che il codice hash di identità per il normale oggetti Java su un sistema a 32 bit viene salvato nella segna la parola ed è lungo 25 bit.

Problemi correlati