Referencias a objetos en Java: Soft, Weak, Phantom

0
6656

En este tutorial veremos los tipos de referencia que mantiene la JVM a los objetos creados y cómo ayuda esto al Garbage Collector en su trabajo de limpieza.

Índice de contenidos

1. Introducción

El concepto de referencia está íntimamente ligado con el comportamiento del recolector de basura. Dependiendo de las referencias que tenga un determinado objeto, este podrá ser elegido para ser limpiado de memoria (referencia débil) o, por el contrario, puede seguir residiendo en el Heap (referencia fuerte).

Cada una de estas referencias denominadas débiles tienen una clase asociada dentro del paquete java.lang.Reference y existen desde la versión 1.2 del JDK.

2. Accesibilidad o Reachability

La propia documentación del paquete java.lang.ref define, en el apartado Reachability, los grados de accesibilidad de más a menos fuertes:

  • Un objeto es accesible de forma fuerte (strongly reachable) si se puede llegar a él sin la necesidad de atravesar ningún objeto de referencia. Un objeto recién creado es accesible de forma fuerte por el hilo que lo creó.
  • Un objeto es accesible de forma soft (softly reachable) si no es accesible de forma fuerte, pero sí a través de una cadena de SoftReferences.
  • Un objeto es accesible de forma débil (weakly reachable) si no es accesible de forma ni fuerte ni soft, pero sí a través de una cadena de WeakReferences. Cuando todas las referencias débiles a un objeto accesible de este tipo desaparecen, este objeto puede ser elegido para su finalización.
  • Un objeto es accesible de forma phantom (phantom reachable) si no es accesible de forma fuerte, soft o débil, ha sido finalizado y existe algún objeto de la clase PhantomReference apuntando al objeto.
  • Por último, un objeto es inaccesible (unreachable) y, por tanto, apto para ser liberado si no puede ser accesible de ninguna de las formas antes descritas.

3. Referencias Fuertes

Las referencias fuertes son las que nos podemos encontrar de forma natural en nuestro código, p.e.:

StringBuilder builder = new StringBuilder();	

Este tipo de referencias hace que el objeto no sea elegible para liberarse o, dicho de otra manera: siempre que un objeto sea referenciado por una cadena de referencias fuertes, no puede ser limpiado del Heap.

4. Referencias Soft

De forma análoga a las referencias fuertes, se puede decir que el Garbage Collector puede liberar un objeto si este está referenciado únicamente por referencias débiles.

El grado más fuerte de este tipo de referencias son las SoftReferences. Los objetos con este tipo de referencias serán liberados únicamente cuando la JVM necesite desesperadamente más memoria.

Las SoftReferences se usan principalmente para implementar cachés simples sensibles al consumo de memoria mediante instancias directas de SoftReference<T>.

Dado el hecho de que mientras el objeto referenciado por una SoftReference sea accesible de forma fuerte esta referencia no será liberada, es posible implementar sistemas de cachés más complejas que, por ejemplo, impidan la finalización de las entradas que se más se han utilizado en los últimos accesos manteniendo referencias fuertes a dichas entradas y dejando a discreción del GC la liberación del resto.

4.1. SoftReferences y el Garbage Collector

Una de las preguntas que suelen surgir cuando uno busca información sobre objetos de referencia en Java y en particular sobre las SoftReference es: ¿cómo y cuándo decide el GC limpiar este tipo de referencias?

Para empezar, la JVM mantiene una variable de tiempo que guarda el momento (en milisegundos desde el inicio de la aplicación) de la última pasada del GC. A su vez, cada SoftReference tiene un campo de timestamp que indica cuándo ella o el objeto referenciado fueron accedidos por última vez. Esto permite una ordenación grosso modo de las SoftReference existentes: el tiempo transcurrido desde el último GC y cada acceso a las referencias.

Cuando un evento del GC se dispara, la decisión de limpiar una SoftReference se basa en dos factores:

  • Hace cuánto se produjo el último acceso a la referencia.
  • Cuánta memoria disponible queda.

Tomando los siguientes parámetros:

  • free_heap es la cantidad de espacio libre en el Heap en MB.
  • interval es el tiempo transcurrido entre la última recolección y el timestamp de la referencia.
  • ms_per_mb es un número constante de milisegundos que determina el tiempo a mantener una SoftReference por cada MB libre en el Heap.

Así, la decisión para limpiar una referencia viene dada por la condición:

interval <= free_heap * ms_per_mb

Por ejemplo, teniendo una SoftReference con un timestamp de 2000ms, la última pasada del GC fué hace 5000ms, el ms_per_mb es 1000 y el espacio libre en el Heap es 1MB:

5000 - 2000 <= 1 * 1000

Ya que 3000 > 1000, la referencia será limpiada.

Una última cosa a tener en cuenta es que las SoftReferences se mantienen siempre durante al menos una pasada del GC después de haber sido accedidas. Esto se debe a que para el cálculo de interval se usa el tiempo de la última recolección, no de la que se esté realizando en ese momento.

5. Referencias Débiles

Como hemos visto antes, un objeto que sólo tenga referencias débiles será liberado por el GC en la siguiente pasada de limpieza. Este tipo puede ser útil, por ejemplo, para almacenar metadatos.

Veamos un pequeño ejemplo para determinar la diferencia entre SoftReference y WeakReference (la referencia débil más fuerte).

Integer significado = new Integer("42");
WeakReference<Integer> referencia = new WeakReference<Integer>(significado);
significado = null;

Una vez que hemos desreferenciado la variable significado, ésta se convierte en apta para ser liberada ya que la única referencia a él es referencia, del tipo WeakReference.

Si ésta variable referencia fuera del tipo SoftReference, como hemos mostrado antes, la siguiente pasada del GC no finalizaría significado.

El ejemplo más conocido de uso de las referencias WeakReference es la clase WeakHashMap. Ésta clase tiene la particularidad de mantener el conjunto de claves mediante WeakReferences, lo que permite la liberación de entradas de forma automática cuando sus claves no se encuentran en uso.

5.1. Referencias Phantom

En el nivel más bajo desde el punto de las referencias débiles se encuentran las PhantomReferences. El significado y la diferencia de este tipo con el resto de las referencias débiles lo veremos en el siguiente apartado.

6. ReferenceQueues – Notificación del grado de accesibilidad

Es posible de manera programática ser avisado de cuando un objeto cambia su accesibilidad, registrando una referencia válida mediante las denominadas colas de referencias o ReferenceQueue en el momento en el que se crea dicha referencia.

En este ámbito es cuándo las PhantomReferences muestran su utilidad. Mientras que el resto de las referencias débiles (WeakReference y SoftReference) son liberadas antes de ser añadidas a una cola de referencias, las PhantomReferences deben ser sacadas de la cola en la que se ha registrado para marcarlas para ser liberadas.

7. Ciclo de vida de un objeto

El siguiente diagrama muestra el ciclo de vida básico por el que pasa un objeto, incluidas las transiciones entre referencias:

referencias-imagen1

8. Conclusión

Conocer la existencia y las diferencias entre los tipos de referencias que mantiene la JVM nos permite idear nuevas formas de trabajar con objetos que no tenemos porque estar manipulando constantemente, de tal manera que la huella que dejamos en memoria en nuestros programas sea lo más eficiente y ligera posible.

9. Fuentes

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad