2010-09-26 10 views
31

Si llamo al método Object.hashcode() en algún objeto, devuelve la dirección interna del objeto (implementación predeterminada). ¿Es esta dirección una dirección lógica o física?Will .hashcode() devolverá un int diferente debido a la compactación del espacio de tenencia?

En la recolección de basura, debido a la compactación de la memoria, los objetos se desplazan en la memoria. Si llamo a hashcode antes y después del GC, ¿devolverá el mismo código hash (regresa) y, en caso afirmativo, entonces por qué (debido a que la dirección de compactación puede cambiar)?

+0

Si imprime el valor de algunos 'Object.hashCode's, probablemente notará que es poco probable que sean direcciones. Números impares en cualquier implementación razonable, por ejemplo. –

Respuesta

41

@erickson es más o menos correcto. El código hash devuelto por java.lang.Object.hashCode() no cambia durante la vida del objeto.

La forma en que esto se implementa (típicamente) es bastante inteligente. Cuando un objeto es reubicado por el recolector de basura, su hashcode original debe almacenarse en algún lugar en caso de que se vuelva a utilizar. La forma obvia de implementar esto sería agregar un campo de 32 bits al encabezado del objeto para contener el código hash. Pero eso agregaría una sobrecarga de 1 palabra a cada objeto, y desperdiciaría espacio en el caso más común ... donde no se llama al método hashCode de un Objeto.

La solución es agregar dos bits de marca a la palabra de bandera del objeto y usarlos (más o menos) de la siguiente manera. El primer indicador se establece cuando se llama al método hashCode. Una segunda bandera le dice al método hashCode si usar la dirección actual del objeto como código hash, o usar un valor almacenado. Cuando el GC se ejecuta y reubica un objeto, prueba estos indicadores. Si se establece el primer indicador y el segundo no está configurado, el GC asigna una palabra adicional al final del objeto y almacena la ubicación del objeto original en esa palabra. Luego establece las dos banderas. A partir de ese momento, el método hashCode obtiene el valor de código hash de la palabra al final del objeto.


De hecho, un identityHashCode aplicación tiene que comportarse de esta manera a satisfacer la siguiente parte de la general hashCode contract:

"Cada vez que se invoca en el mismo objeto más de una vez durante una ejecución de una aplicación Java, el método hashCode debe devolver consistentemente el mismo entero, siempre que no se modifique ninguna información utilizada en comparaciones iguales en el objeto. Este número entero no necesita ser consistente desde una ejecución de una aplicación a otra ejecución de la misma aplicación ".

Una aplicación hipotética de identityHashCode() que simplemente devuelve la dirección de la máquina actual de un objeto violaría la parte resaltada si/cuando el GC se trasladó el objeto a una dirección diferente. La única forma de evitar esto sería que la JVM (hipotética) garantice que un objeto nunca se mueve una vez que se ha invocado hashCode. Y eso llevaría a problemas serios e intratables con la fragmentación del montón.

+1

Gran explicación Stephen! Su descripción del funcionamiento de hashCode() aclara cómo hashCode() conserva el mismo valor durante la ejecución del programa. Mientras tanto, si se produce una compactación de memoria GC + y un nuevo objeto (cuyo hashCode() no se ha invocado aún) se le asigna el mismo espacio que el anterior, entonces el valor hashCode() no sería el mismo que el del objeto activo que inicialmente ocupó la ubicación de la memoria? ¿Cómo afecta esto la igualdad de objetos y las colecciones basadas en hash? –

+0

Eso se explica por el 3er párrafo de mi respuesta. Básicamente, la dirección/código hash original se almacena al final del objeto cuando se reubica. Pero solo cuando sea necesario; es decir, solo si se ha llamado * identityHashcode() '*. –

+0

Lo que quise decir es que Object1 tiene hasCode 100 y esto se copia en la palabra adicional al final de Object1. En este punto, suponga que se produce una compactación de GC y Object1 se desplaza a otro lugar, liberando su ubicación de memoria original para nuevas asignaciones. Supongamos que debido a alguna coincidencia, el nuevo Object2 se asigna de alguna manera en la ubicación anterior de Object1. ¿Cuál será el hashCode de Object2? ¿no será 100? TH \ his significaría que Object1 (ahora se movió a otra parte, pero que hashCode 100 se guardó en la última palabra) y Object2 (asignado en la ubicación anterior de Object1) compartirán el mismo hashCode. –

0

En este link dice que, de hecho, el código hash predeterminado es la dirección JVM del objeto, pero si se mueve, la dirección permanece constante. No sé qué tan confiable es esta fuente, pero estoy seguro de que los implementadores de este método pensaron en este escenario (que no es raro ni en el caso de esquina), y garantizaron la funcionalidad correcta de este método.

4

No, el código hash predeterminado de un objeto no cambiará.

La documentación no dice que el código hash es la dirección, se dice que es basado en la dirección. Tenga en cuenta que los códigos hash son 32 bits, pero hay JVM de 64 bits. Claramente, el uso directo de la dirección no siempre funcionaría.

La implementación depende de la JVM, pero en la JVM de Sun (Oracle), creo que el código hash se almacena en caché la primera vez que se accede a él.

+1

Desde Java Doc de hashCode: Esto normalmente se implementa convirtiendo la dirección interna del objeto en un número entero – Ashish

+0

en realidad, el hashcode se almacena en caché cuando el GC reubica un objeto ... si 'hashcode()' ha sido llamado previamente. –

+0

En realidad, Ashish, el javadoc dice esto: "Esto se implementa típicamente convirtiendo la dirección interna del objeto en un entero, ** pero esta técnica de implementación no es requerida por el lenguaje de programación Java ™. **" De hecho, las JVM recientes tienen una opción de línea de comando que le permite elegir otros métodos para generar hashcodes. –

-1

si el hashcode cambia, el objeto desaparecerá en un hash en el que se insertó, y Sun se inundará de quejas.

0

Por el contrato de hashCode no puede cambiar por tal motivo.

Cuestiones relacionadas