ejemplo - liberar memoria java
¿Variable=null lo establece para la recolección de basura (8)
Ayúdeme a resolver una disputa con un compañero de trabajo: ¿Establecer una variable o colección para anular la ayuda de Java en la recolección de basura y reducir el uso de memoria? Si tengo un programa de larga ejecución y cada función puede ser llamada iterativamente (potencialmente miles de veces): ¿Establecer nulos todas las variables en él antes de devolver un valor a la función principal ayuda a reducir el uso de memoria / tamaño de pila?
Del artículo:
Hay un caso en el que el uso de anulación explícita no solo es útil, sino que es prácticamente obligatorio, y es allí donde una referencia a un objeto tiene un alcance más amplio que el utilizado o considerado válido por las especificaciones del programa. Esto incluye casos como el uso de un campo estático o de instancia para almacenar una referencia a un búfer temporal, en lugar de una variable local, o el uso de una matriz para almacenar referencias que pueden permanecer accesibles por el tiempo de ejecución pero no por la semántica implícita del programa.
Traducción: objetos persistentes "explícitamente nulos" que ya no son necesarios. (Si lo desea. "¿Es prácticamente obligatorio?" Una afirmación demasiado fuerte?)
Es bueno tenerlo Cuando establece los objetos como nulos, existe la posibilidad de que el objeto pueda ser recogido más rápidamente, en el ciclo GC inmediato. Pero no hay un mecanismo garantizado para hacer que un objeto sea recogido en un momento dado.
Es inútil en variables locales, pero puede ser útil / necesario para borrar variables de instancia que ya no son necesarias (por ejemplo, post-inicialización).
(Sí, sí, sé cómo aplicar el patrón Builder ...)
Eso solo podría tener algún sentido en un escenario como este:
public void myHeavyMethod() {
List hugeList = loadHugeListOfStuff(); // lots of memory used
ResultX res = processHugeList(hugeList); // compute some result or summary
// hugeList = null; // we are done with hugeList
...
// do a lot of other things that takes a LOT of time (seconds?)
// and which do not require hugeList
...
}
Aquí podría ser beneficioso descomentar la línea hugeList = null
, supongo.
Pero ciertamente tendría más sentido reescribir el método (tal vez refactorizar en dos o especificar un alcance interno).
Establecer una referencia de objeto a null solo lo hace elegible para la recolección de basura. No libera necesariamente la memoria, que depende de cuándo se ejecuta el recolector de elementos no utilizados (que depende de JVM). Cuando se ejecuta el recolector de elementos no utilizados, libera el montón al eliminar solo los objetos que son elegibles para la recolección de elementos no utilizados.
La especificación de VM de Java
12.6.1 Implementación de la finalización Cada objeto se puede caracterizar por dos atributos: puede ser accesible, finalizador alcanzable o inalcanzable, y también puede estar finalizado, finalizable o finalizado.
Un objeto accesible es cualquier objeto al que se pueda acceder en cualquier cómputo potencial continuo desde cualquier hilo en vivo . Se pueden diseñar transformaciones de optimización de un programa que reduzcan la cantidad de objetos accesibles para que sean inferiores a los que ingenuamente se considerarían alcanzables. Por ejemplo, un compilador o generador de código puede optar por establecer una variable o parámetro que ya no se utilizará para anular para hacer que el almacenamiento de dicho objeto sea potencialmente recuperable antes.
Discusión
Otro ejemplo de esto ocurre si los valores en los campos de un objeto se almacenan en registros. El programa puede entonces acceder a los registros en lugar del objeto, y nunca volver a acceder al objeto. Esto implicaría que el objeto es basura.
El objeto es alcanzable si puede estar involucrado en cualquier posible cálculo continuo. Por lo tanto, si su código hace referencia a una variable local y no se refiere a nada más, puede hacer que el objeto se recopile configurándolo como nulo. Esto daría una excepción de puntero nulo o cambiaría el comportamiento de su programa, o si no lo hace, no necesita la variable en primer lugar.
Si anula un campo o un elemento de matriz, posiblemente tenga sentido para algunas aplicaciones y hará que la memoria se reclame más rápido. Una vez que Case está creando una gran matriz para reemplazar una matriz existente referenciada por un campo en una clase, si el campo en nulled antes de la sustitución se crea, entonces puede aliviar la presión sobre la memoria.
Otra característica interesante de Java es que el alcance no aparece en los archivos de clase, por lo que el alcance no es relevante para la accesibilidad; estos dos métodos crean el mismo bytecode y, por lo tanto, la VM no ve en absoluto el alcance del objeto creado:
static void withBlock () {
int x = 1;
{
Object a = new Object();
}
System.out.println(x+1);
}
static void withoutBlock () {
int x = 1;
Object a = new Object();
System.out.println(x+1);
}
No necesariamente. Un objeto se vuelve elegible para la recolección de basura cuando ya no hay subprocesos activos que contienen una referencia al objeto.
Las variables locales salen del alcance cuando el método retorna y no tiene ningún sentido establecer variables locales en nulo: las variables desaparecen de todos modos, y si no hay nada más que contenga una referencia de los objetos a los que se refieren las variables, entonces esos objetos se vuelven elegible para la recolección de basura.
La clave no es mirar solo las variables, sino observar los objetos a los que se refieren esas variables, y descubrir a qué objetos hace referencia su programa.
Esa es la vieja tradición del rendimiento. Fue cierto en 1.0 días, pero el compilador y la JVM se han mejorado para eliminar la necesidad (si alguna vez hubo uno). Este excelente artículo de IBM entra en detalles si está interesado: teoría y práctica de Java: recolección de basura y rendimiento