"¡Hola! Decidí darte otra pequeña lección sobre la recolección de basura".

Como ya sabe, la propia máquina Java supervisa cuándo un objeto se vuelve innecesario y lo elimina.

"Sí. Rishi y tú me lo contaron antes. No recuerdo los detalles".

"Está bien. Entonces repasemos de nuevo".

Recolección de basura - 1

"Tan pronto como se crea un objeto, la JVM le asigna memoria. El interés en el objeto se controla mediante variables de referencia.  Un objeto se puede eliminar durante la recolección de basura, es decir, el procedimiento mediante el cual se libera memoria si no hay variables que hagan referencia al objeto " .

"Cuéntame un poco sobre el recolector de basura: qué es y cómo funciona".

"Está bien. La recolección de basura solía ocurrir en el subproceso principal. Cada 5 minutos, o más a menudo. Si alguna vez no había suficiente memoria libre, la máquina Java suspendía todos los subprocesos y eliminaba los objetos no utilizados".

"Pero este enfoque se ha abandonado ahora. El recolector de basura de próxima generación funciona detrás de escena y en un hilo separado. Esto se llama recolección de basura concurrente".

"Ya veo. ¿Cómo se toma exactamente la decisión de eliminar o no un objeto?"

"Simplemente contar el número de referencias a un objeto no es muy efectivo; puede haber objetos que se referencian entre sí, pero no son referenciados por otros objetos".

"Entonces, Java adopta un enfoque diferente.  Java divide los objetos en accesibles e inalcanzables.  Un objeto es accesible (vivo) si otro objeto accesible (vivo) hace referencia a él. La accesibilidad se determina a partir de los subprocesos. Los subprocesos en ejecución siempre se consideran accesibles (vivos) , incluso si nadie hace referencia a ellos".

"Está bien. Creo que lo entiendo".

"¿Cómo ocurre la recolección de basura real: la eliminación de objetos innecesarios?"

"Es simple. En Java, la memoria se divide en dos partes por convención, y cuando llega el momento de la recolección de basura, todos los objetos vivos (accesibles) se copian en otra parte de la memoria, y la memoria anterior se libera".

"Ese es un enfoque interesante. No es necesario contar las referencias: copie todos los objetos accesibles, y todo lo demás es basura".

"Es un poco más complicado que eso. Los programadores de Java descubrieron que los objetos generalmente se dividen en dos categorías: de larga duración (que existen durante todo el tiempo que se ejecuta el programa) y de corta duración (que son necesarios en los métodos y para realizar tareas "locales". » operaciones)."

"Es mucho más eficiente mantener los objetos de vida larga separados de los de vida corta. Para hacer esto, fue necesario encontrar una forma de determinar la longevidad del objeto".

"Entonces, dividieron toda la memoria en "generaciones". Hay objetos de primera generación, objetos de segunda generación, etc. Cada vez que se borra la memoria, el contador de generación se incrementa en 1. Si ciertos objetos existen en varias generaciones, entonces se registran como longevos".

"Hoy, el recolector de basura es una parte muy compleja y eficiente de Java. Muchas de sus partes funcionan de forma heurística, basadas en algoritmos que hacen conjeturas. Como resultado, a menudo "no escucha" al usuario".

"¿Significado?"

"Java tiene un objeto recolector de basura ( GC ) que se puede llamar usando el método System.gc ()".

"También puede usar System.runFinalization() para forzar que se eliminen las llamadas a los métodos finalize de los objetos. Pero el hecho es que, según la documentación de Java, esto no garantiza que se inicie la recolección de basura, ni que finalize( ) se llamará al método.  El recolector de basura decide cuándo llamarlo y en qué " .

"¡Vaya! Es bueno saberlo".

"Pero hay más. Como sabes, en Java, algunos objetos hacen referencia a otros. Esta red de referencias se usa para determinar si un objeto debe eliminarse".

"Y, mira. Java tiene referencias especiales que te permiten influir en este proceso. Hay clases contenedoras especiales para ellas. Aquí están:"

" SoftReference  es una referencia suave".

" WeakReference  es una referencia débil".

" PhantomReference es una referencia fantasma".

"Uh... Esto me recuerda a las clases internas, las clases anidadas, las clases anónimas anidadas y las clases locales. Los nombres son diferentes, pero no está del todo claro para qué sirven".

"Dime, Amigo, te has convertido en programador. Ahora estás enojado por los nombres de las clases, diciendo "no son lo suficientemente informativos, y es imposible con un nombre (!) Determinar qué hace esta clase, cómo, y por qué"."

"Wow. Ni siquiera me di cuenta. Pero es tan obvio".

"Está bien. Basta de palabras. Déjame hablarte de SoftReferences".

"Estas referencias se diseñaron específicamente para el almacenamiento en caché, aunque se pueden usar para otros fines, todo a discreción del programador".

"Aquí hay un ejemplo de tal referencia:"

Ejemplo
// Create a Cat object
Cat cat = new Cat();

// Create a soft reference to a Cat object
SoftReference<Cat> catRef = new SoftReference<Cat>(cat);

// Now only the catRef soft reference points at the object
cat = null;

// Now the ordinary cat variable also references the object
cat = catRef.get();

// Clear the soft reference
catRef.clear();

"Si las únicas referencias a un objeto son suaves, entonces continúa vivo y se llama 'alcanzable suavemente'".

"¡Pero!  El recolector de elementos no utilizados puede eliminar un objeto al que solo se hace referencia mediante referencias suaves si el programa no tiene suficiente memoria.  Si de repente el programa no tiene suficiente memoria, antes de lanzar una OutOfMemoryException , el recolector de elementos no utilizados eliminará todos los objetos referenciado por referencias blandas e intentará nuevamente asignar memoria al programa".

"Supongamos que un programa cliente solicita con frecuencia varios datos de un programa servidor. El programa servidor puede usar una SoftReference para almacenar en caché algunos de ellos. Si los objetos que las referencias blandas evitan que mueran ocupan una gran parte de la memoria, entonces el recolector de basura simplemente los elimina. todo. ¡Es hermoso!"

"Sí. A mí también me gustó".

"Bueno, una pequeña adición: la clase SoftReference tiene dos métodos. El método get() devuelve el objeto al que hace referencia SoftReference . Si el recolector de basura eliminó el objeto, el método get () de repente comenzará a devolver un valor nulo".

"El usuario también puede borrar SoftReference explícitamente llamando al método clear(). En este caso, se destruirá el vínculo débil dentro del objeto SoftReference ".

"Eso es todo por ahora."

"Gracias por la interesante historia, Ellie. Realmente fue muy interesante".