El recolector de basura en Java es automático, es decir, el usuario no tiene que liberar manualmente una memoria ocupada que se asignó dinámicamente. ¿Y cómo decide un recolector de basura qué objeto debe eliminarse? Es simple: el objeto que pierde su referencia, se marca para su eliminación de la memoria del montón. Por ejemplo, observe el siguiente fragmento de código:
// Java code to demonstrate when an object would // be deleted by the garbage collector class A { void f() { A x = new A(); /*object created locally It's scope remains valid till the termination of this function*/ } public static void main(String a[]) { f(); /* function f() terminates, and hence the object 'x' too gets collected by the garbage collector*/ } }
El código anterior muestra que la variable de referencia ‘x’ tenía un alcance limitado a la función ‘f()’. Por lo tanto, después de la terminación de la función mencionada, la variable tampoco tiene reconocimiento. Por lo tanto, el objeto creado pierde su referencia y, por lo tanto, es recolectado por el recolector de basura.
Los objetos que recopila el recolector de elementos no utilizados se recopilan para liberar la memoria del montón, donde se asigna la memoria dinámica. El siguiente diagrama explica los diferentes segmentos de memoria en un programa Java y sus usos:
Sin embargo, a veces surge la pregunta: ‘¿Hay alguna manera de evitar que el recolector de basura recoja un objeto?’
Hay varias formas de hacer que los objetos no se puedan eliminar en Java. Se discuten a continuación:
Al aumentar la memoria del montón
Java asigna memoria a su objeto en una partición llamada ‘montón’ (a excepción de String y algunos otros objetos especiales a los que se les asigna memoria en el grupo). Dado que la memoria del montón es limitada, siempre se necesita liberar algo de memoria para acomodar espacio para nuevos objetos. Sin embargo, podemos, hasta cierto punto, hacer que los objetos no se puedan eliminar aumentando el tamaño del almacenamiento dinámico. Los siguientes parámetros de la línea de comandos de jvm pueden hacer el trabajo:
- xms
- xmx
Xmx especifica el grupo de asignación de memoria máxima para una máquina virtual Java (JVM), mientras que Xms especifica el grupo de asignación de memoria inicial. Lo siguiente es un ejemplo:
java -Xms256m -Xmx2048m classfile
Aquí, en el ejemplo anterior, comienza con 256 MB de memoria en montón asignada inicialmente, que podría expandirse hasta un máximo de 2048 MB de tamaño de montón.
Este enfoque hace que el recolector de elementos no utilizados se ejecute con poca frecuencia; sin embargo, cuando se ejecuta, tardará más que antes en completar la tarea de recolección de elementos no utilizados.
Mediante el uso de la clase Singleton
En el caso de una clase singleton, la referencia del único objeto creado se puede almacenar en una referencia estática. Dado que los miembros estáticos se almacenan en el área de clase (un segmento de memoria), su vida útil abarca la vida útil del programa. El siguiente programa explica cómo hacerlo:
public class Singleton { /* static class member which will store the object reference*/ private static Singleton uniqueInstance; private Singleton() { } public static synchronized Singleton getInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqInstance; } }
El ejemplo anterior muestra que, dado que la referencia del objeto se ha pasado a una variable estática, nunca se perderá. Por lo tanto, el objeto no se eliminará hasta el final del programa. Sin embargo, el único problema es que solo se puede crear un objeto aquí.
Usando public void finalise()
Finalize es un método de devolución de llamada (un método llamado por la JVM, y no por el usuario), que es el último método ejecutado en un objeto. Una subclase puede anular el método de finalización para deshacerse de los recursos del sistema o para realizar otra limpieza.
¿Cómo evitar la recolección de basura usando finalizar?
El método de finalización de una clase se puede anular para conservar la referencia del objeto que está a punto de eliminarse. El siguiente programa demuestra cómo:
// Java code to demonstrate how to prevent garbage collection // of an object using finalize method class A { static A y; void f() { A x = new A(); } pubic void finalize() { y = this; // Putting the reference id // of the current object // into the static variable y System.out.println("Object reference saved. The object won't be collected by the garbage collector"); } public static void main(String a[]) { f(); // function called }
Producción:
Object reference saved. The object won't be collected by the garbage collector
Como se explicó anteriormente, finalizar es el último método que se ejecuta en un objeto. En el programa anterior, la función ‘f()’ crea un objeto local de clase A. Cuando finaliza la llamada de la función, el alcance de la variable ‘x’ también finaliza y, por lo tanto, se marca para su recolección por la basura coleccionista. Sin embargo, antes de que el recolector de elementos no utilizados pueda eliminar el objeto, finalice las ejecuciones.
Dentro del cuerpo del método ‘finalizar’, se puede ver que al miembro estático de la clase A, ‘y’, se le asigna la identificación de referencia del objeto actual. Como resultado, la identificación de referencia del objeto que se eliminará se conserva y, por lo tanto, el objeto no se elimina.
Sin embargo, es muy importante saber que hacer que un objeto no se pueda eliminar es arriesgado y aumenta las posibilidades de pérdidas de memoria. Por lo tanto, no es recomendable hacerlo.