Comprensión de las clases de referencia de Java: SoftReference, WeakReference y PhantomReference

81

¿Alguien puede explicar la diferencia entre las tres clases de referencia (o publicar un enlace a una buena explicación)? SoftReference> WeakReference> PhantomReference, Pero cuando iba a utilizar cada uno? ¿Por qué hay un WeakHashMappero no SoftHashMapo PhantomHashMap?

Y si uso el siguiente código ...

WeakReference<String> ref = new WeakReference<String>("Hello!");
if (ref != null) {                 // ref can get collected at any time...
    System.gc();                   // Let's assume ref gets collected here.
    System.out.println(ref.get()); // Now what?!
}

...¿lo que pasa? ¿Tengo que verificar si refes nulo antes de cada declaración (esto está mal, pero qué debo hacer)? Perdón por las preguntas rápidas, pero tengo problemas para entender estas Referenceclases ... ¡Gracias!

Haywood Jablomey
fuente
1
¿Por qué hay una pregunta WeakHashMappero no SoftHashMapo PhantomHashMapExcelente, por qué no me di cuenta de esto antes ... ??
Mehraj Malik
1
El ref != nullcheque no tiene sentido. refnunca lo será null.
Holger
añadiendo a la Q: strongRef --> weakRef --> objA. Ahora, será objAGCed o no, ya que tiene una referencia indirecta de strongRef.
samshers

Respuestas:

60

La documentación de lajava.lang.ref biblioteca de Java para el paquete caracteriza la fuerza decreciente de los tres tipos de referencia explícitos.

Utiliza un SoftReferencecuando desea que el objeto referenciado permanezca activo hasta que el proceso del host se esté quedando sin memoria. El objeto no será elegible para la recopilación hasta que el recopilador necesite liberar memoria. Enunciado libremente, vincular un SoftReferencemedio, "Fija el objeto hasta que no puedas más".

Por el contrario, utilice a WeakReferencecuando no desee influir en la vida útil del objeto al que se hace referencia; simplemente desea hacer una afirmación separada sobre el objeto al que se hace referencia, siempre que permanezca vivo. La elegibilidad del objeto para la colección no está influenciada por la presencia de enlaces WeakReference. Algo así como un mapeo externo de la instancia del objeto a la propiedad relacionada, donde la propiedad solo necesita registrarse mientras el objeto relacionado esté vivo, es un buen uso para WeakReferences y WeakHashMap.

El último ... PhantomReferencees más difícil de caracterizar. Por WeakReferenceejemplo, tal límite PhantomReferenceno ejerce ninguna influencia en la vida útil del objeto referenciado. Pero a diferencia de los otros tipos de referencia, ni siquiera se puede eliminar la referencia a PhantomReference. En cierto sentido, no apunta a lo que apunta, por lo que las personas que llaman pueden saber. Simplemente le permite a uno asociar algunos datos relacionados con el objeto referenciado, datos que luego se pueden inspeccionar y actuar sobre ellos cuando PhantomReferencese pone en cola en su relacionado ReferenceQueue. Normalmente, se deriva un tipo PhantomReferencee incluye algunos datos adicionales en ese tipo derivado. Desafortunadamente, hay algo de abatimiento involucrado para hacer uso de un tipo derivado.

En su código de ejemplo, no es la refreferencia (o, si lo prefiere, la "variable") la que puede ser nula. Más bien, es el valor obtenido al llamar Reference#get()que puede ser nulo. Si se determina que es nulo, es demasiado tarde; el objeto referenciado ya está en camino de ser recopilado:

final String val = ref.get();
if (null != val)
{
  // "val" is now pinned strongly.
}
else
{
  // "val" is already ready to be collected.
}
seh
fuente
añadiendo a la Q: strongRef --> weakRef --> objA. Ahora, será objAGCed o no, ya que tiene una referencia indirecta de strongRef.
samshers
Si entiendo correctamente su pregunta, @samshers, objAes elegible para la recolección como basura. Fijar un WeakReferenceno ejerce ninguna influencia sobre el objeto al que WeakReferenceapunta.
seh
No tener una referencia fuerte en la cadena hace la diferencia. Porque para objAque se recolecte basura, la referencia débil debe eliminarse primero a la derecha. Y una fuerte referencia está apuntando a los débiles referencia por el que los débiles no elegible para ser ref GCed
samshers
No, WeakReferenceno es necesario recolectarlo para permitir objAsu recolección. El WeakReferenceno se mantiene objAvivo. Más bien, es una forma de encontrar objAmientras está vivo, sin influir en esa vida, y detectar cuándo el coleccionista ya se lo llevó.
seh
6

Un enlace: https://community.oracle.com/blogs/enicholas/2006/05/04/understanding-weak-references

PhantomHashMapNo funcionaría muy bien, ya que getsiempre devuelve nullpara referencias fantasmas.

Los cachés son difíciles, por lo SoftHashMapque es posible que no funcionen tan bien como crees. Sin embargo, creo que la biblioteca de colecciones de Google contiene una implementación de mapa de referencia general.

Siempre debe verificar que getdevuelve no- null. (Tenga en cuenta que no comprobar que la Referencereferencia en sí no sea- null.) En el caso de cadenas internas, siempre lo hará, pero (como siempre) no intente ser "inteligente" al respecto.

Tom Hawtin - tackline
fuente
El enlace ha caducado.
Mehraj Malik
@MehrajMalik Enlace fijo.
Tom Hawtin - tackline
añadiendo a la Q: strongRef --> weakRef --> objA. Ahora, será objAGCed o no, ya que tiene una referencia indirecta de strongRef.
samshers
0
String str = new String("hello, world");
WeakReference<String> ref = new WeakReference<String>(str);
str = null;

if (ref != null) {                 
    System.gc(); 
    System.out.println(ref.get());
}

En este caso, generará un valor nulo. La llamada a System.gc()es importante aquí.

kopite
fuente