Comprender las clases de referencia de Java: SoftReference, WeakReference y PhantomReference
weak-references phantom-reference (4)
¿Alguien puede explicar la diferencia entre las tres clases de referencia (o publicar un enlace a una buena explicación)? SoftReference
> WeakReference
> PhantomReference
, pero ¿cuándo usaría cada uno? ¿Por qué hay un WeakHashMap
pero no SoftHashMap
o 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 ref
es nulo antes de cada declaración (esto es incorrecto, pero qué debo hacer)? Perdón por las preguntas rápidas, pero estoy teniendo problemas para entender estas clases de Reference
... ¡Gracias!
La documentación de la biblioteca Java para el paquete java.lang.ref
caracteriza la fortaleza decreciente de los tres tipos de referencia explícitos.
Utiliza una SoftReference
cuando desea que el objeto al que se hace referencia 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 recolector necesite liberar memoria. En SoftReference
, vincular una SoftReference
significa, "Pin el objeto hasta que no puedas más".
Por el contrario, utilice una WeakReference
cuando no desee influir en la duración del objeto al que se hace referencia; simplemente desea hacer una afirmación separada sobre el objeto al que se hace referencia, mientras siga vivo. La elegibilidad del objeto para la recopilación no está influenciada por la presencia de WeakReference
vinculadas. Algo así como un mapeo externo desde la instancia del objeto a la propiedad relacionada, donde la propiedad solo necesita ser registrada siempre y cuando el objeto relacionado esté vivo, es un buen uso para WeakReference
y WeakHashMap
.
La última, PhantomReference
es más difícil de caracterizar. Al igual que WeakReference
, una PhantomReference
enlazada no ejerce ninguna influencia sobre la duración del objeto al que se hace referencia. Pero a diferencia de los otros tipos de referencia, uno ni siquiera puede desreferenciar una referencia PhantomReference
. En cierto sentido, no apunta a lo que apunta, por lo que los que llaman pueden decir. Simplemente permite asociar algunos datos relacionados con el objeto al que se hace referencia, datos que luego pueden ser inspeccionados y PhantomReference
cuando PhantomReference
se pone en cola en su ReferenceQueue
relacionada. Normalmente, uno deriva un tipo de PhantomReference
e incluye algunos datos adicionales en ese tipo derivado. Desafortunadamente, hay un poco de downcasting involucrado para hacer uso de dicho tipo derivado.
En su código de ejemplo, no es la ref
referencia (o, si lo prefiere, "variable") que puede ser nula. Más bien, es el valor obtenido llamando a Reference#get()
que puede ser nulo. Si se descubre que es nulo, ya es demasiado tarde; el objeto al que se hace referencia ya está en camino a ser recolectado:
final String val = ref.get();
if (null != val)
{
// "val" is now pinned strongly.
}
else
{
// "val" is already ready to be collected.
}
También se debe mencionar, como se indica en el comentario de Truong Xuan Tinh, aquí: http://blog.yohanliyanage.com/2010/10/ktjs-3-soft-weak-phantom-references/
JRockit JVM implementa referencias débiles / suaves / fantasmas de forma diferente a Sun JVM.
Un enlace: https://community.oracle.com/blogs/enicholas/2006/05/04/understanding-weak-references
PhantomHashMap
no funcionaría muy bien, ya get
siempre devuelve null
para referencias fantasmas.
Los cachés son difíciles, por lo que SoftHashMap
podría no funcionar tan bien como crees. Sin embargo, creo que la biblioteca de colecciones de Google contiene una implementación general del mapa de referencia.
Siempre debe verificar que get
devoluciones no null
. (Tenga en cuenta que no verifica que la Reference
referencia en sí misma no sea null
). En el caso de cadenas internas, siempre lo hará, pero (como siempre) no trate de ser "inteligente" al respecto.
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á nulo. Y System.gc () es importante aquí.