In che modo la JVM garantisce che System.identityHashCode () non cambierà mai?

In genere l’implementazione predefinita di Object.hashCode() è una funzione Object.hashCode() assegnata dell’object in memoria (sebbene questo non sia richiesto dal JLS ). Dato che la VM smuove gli oggetti in memoria, perché il valore restituito da System.identityHashCode() non cambia mai durante la vita dell’object?

Se si tratta di un calcolo “one-shot” (l’ hashCode dell’object viene calcolato una volta e nascosto nell’intestazione dell’object o qualcosa del genere), vuol dire che è ansible che due oggetti abbiano lo stesso identityHashCode (se vengono assegnati per primi allo stesso indirizzo in memoria)?

Le moderne JVM salvano il valore nell’intestazione dell’object. 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’identity framework sia sempre 1 per tutti gli oggetti.

Più oggetti possono avere lo stesso codice di hash dell’id quadro. Questa è la natura dei codici hash.

In risposta alla seconda domanda, indipendentemente dall’implementazione, è ansible che più oggetti abbiano la stessa identityHashCode.

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

L’intestazione di un object in HotSpot è composta da un puntatore di class e una parola “segno”.

Il codice sorgente della struttura dati per la parola markOop.hpp può essere trovato nel file markOop.hpp . In questo file c’è un commento che descrive il layout di memoria della parola mark:

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

Qui possiamo vedere che il codice di hash dell’id quadro per oggetti Java normali su un sistema a 32 bit viene salvato nella parola mark ed è lungo 25 bit.

Le linee guida generali per l’implementazione di una funzione di hashing sono:

  • lo stesso object dovrebbe restituire un hashCode coerente , non dovrebbe cambiare nel tempo o dipendere da qualsiasi informazione variabile (ad esempio un algoritmo seminato da un numero casuale o valori di campi membri mutabili
  • la funzione di hash dovrebbe avere una buona distribuzione casuale , e con questo intendo se consideri l’hashcode come bucket, 2 oggetti dovrebbero mappare su diversi bucket (hashcode) il più lontano ansible. La possibilità che 2 oggetti abbiano lo stesso hashcode dovrebbe essere rara, sebbene possa accadere.

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