que - ¿Cómo liberar memoria en Java?
destruir objeto android (13)
* "Confío personalmente en anular variables como un marcador de posición para una eliminación correcta futura. Por ejemplo, me tomo el tiempo para anular todos los elementos de una matriz antes de eliminar (hacer nulo) la matriz en sí misma".
Esto es innecesario. La forma en que funciona el GC de Java es que encuentra objetos que no tienen referencia para ellos, así que si tengo un Objeto x con una referencia (= variable) a que lo apunte, el GC no lo eliminará, porque hay una referencia a ese objeto:
a -> x
Si anulas un, esto sucede:
a -> null
x
Entonces ahora x no tiene una referencia que lo apunte y será eliminado. Lo mismo ocurre cuando configura una referencia a un objeto diferente de x.
Entonces, si tiene una matriz arr que hace referencia a los objetos x, y y z y una variable a que hace referencia a la matriz, se ve así:
a -> arr -> x
-> y
-> z
Si anulas un, esto sucede:
a -> null
arr -> x
-> y
-> z
Entonces, el GC encuentra que arr no tiene referencia establecida y lo elimina, lo que le da esta estructura:
a -> null
x
y
z
Ahora el GC encuentra x, y y z y los elimina también. Anular cada referencia en la matriz no mejorará nada, solo usará el tiempo y el espacio de la CPU en el código (dicho esto, no va a doler más.) El GC aún podrá funcionar de la manera que debería. )
¿Hay alguna forma de liberar memoria en Java, similar a la función free()
C? ¿O está configurando el objeto como nulo y confiando en GC la única opción?
Aunque Java proporciona recolección automática de basura, a veces querrás saber qué tan grande es el objeto y cuánto queda. Memoria libre usando programáticamente import java.lang;
y Runtime r=Runtime.getRuntime();
para obtener valores de memoria usando mem1=r.freeMemory();
para liberar memoria, llame al r.gc();
método y la llamada freeMemory()
En mi caso, dado que mi código Java está destinado a ser portado a otros idiomas en el futuro cercano (principalmente C ++), al menos quiero fingir que la memoria se libera correctamente, por lo que ayuda más tarde en el proceso de portado.
Personalmente confío en anular variables como un marcador de posición para una eliminación adecuada en el futuro. Por ejemplo, me tomo el tiempo para anular todos los elementos de una matriz antes de eliminar (hacer nulo) la matriz en sí misma.
Pero mi caso es muy particular, y sé que estoy recibiendo éxitos de rendimiento al hacer esto.
Enteramente de javacoffeebreak.com/faq/faq0012.html
Un subproceso de baja prioridad se ocupa de la recolección de basura automáticamente para el usuario. Durante el tiempo de inactividad, se puede invocar el subproceso y puede comenzar a liberar memoria previamente asignada a un objeto en Java. Pero no te preocupes: ¡no borrará tus objetos!
Cuando no hay referencias a un objeto, se convierte en juego limpio para el recolector de basura. En lugar de llamar a alguna rutina (como gratuita en C ++), simplemente asigna todas las referencias al objeto a nulo, o asigna una nueva clase a la referencia.
Ejemplo:
public static void main(String args[]) { // Instantiate a large memory using class MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192); // Do some work for ( .............. ) { // Do some processing on myClass } // Clear reference to myClass myClass = null; // Continue processing, safe in the knowledge // that the garbage collector will reclaim myClass }
Si su código está a punto de solicitar una gran cantidad de memoria, puede solicitar al recolector de basura que comience a reclamar espacio, en lugar de permitir que lo haga como un hilo de baja prioridad. Para hacer esto, agregue lo siguiente a su código
System.gc();
El recolector de elementos no utilizados intentará reclamar espacio libre, y la aplicación puede seguir ejecutándose, con la mayor recuperación de memoria posible (es posible que se apliquen problemas de fragmentación de memoria en ciertas plataformas).
He hecho experimentación en esto.
Es cierto que System.gc();
solo sugiere ejecutar el Recolector de basura.
Pero llamando a System.gc();
después de establecer todas las referencias a null
, mejorará el rendimiento y la ocupación de la memoria.
Java usa memoria administrada, por lo que la única forma de asignar memoria es mediante el uso del new
operador, y la única manera de desasignar la memoria es confiar en el recolector de basura.
Este documento técnico de administración de memoria (PDF) puede ayudar a explicar lo que está sucediendo.
También puede llamar a System.gc()
para sugerir que el recolector de basura se ejecute inmediatamente. Sin embargo, Java Runtime toma la decisión final, no su código.
De acuerdo con la documentación de Java ,
Llamar al método gc sugiere que la Máquina Virtual Java gasta esfuerzos para reciclar objetos no utilizados a fin de que la memoria que ocupan actualmente esté disponible para su reutilización rápida. Cuando el control vuelve de la llamada al método, la Máquina Virtual Java ha hecho un gran esfuerzo para reclamar espacio de todos los objetos descartados.
La recomendación de JAVA es asignar a nulo
Desde https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
Asignar explícitamente un valor nulo a las variables que ya no se necesitan ayuda al recolector de basura a identificar las partes de la memoria que se pueden recuperar de forma segura. Aunque Java proporciona administración de memoria, no evita fugas de memoria ni usa cantidades excesivas de memoria.
Una aplicación puede inducir fugas de memoria al no liberar referencias de objetos. Al hacerlo, se evita que el recolector de basura de Java reclame esos objetos, y los resultados en el aumento de la cantidad de memoria utilizada. Anular explícitamente las referencias a las variables después de su uso permite que el recolector de basura reclame la memoria.
Una forma de detectar fugas de memoria es emplear herramientas de creación de perfiles y tomar instantáneas de memoria después de cada transacción. Una aplicación libre de fugas en estado estacionario mostrará una memoria de pila activa y estable después de las recolecciones de basura.
Nadie parece haber mencionado explícitamente el establecimiento de referencias de objeto a null
, que es una técnica legítima para "liberar" la memoria que tal vez desee considerar.
Por ejemplo, supongamos que declaró una List<String>
al comienzo de un método que creció en tamaño para ser muy grande, pero solo fue necesario hasta la mitad del método. En este punto, podría establecer la referencia de la Lista como null
para permitir que el recolector de basura reclame potencialmente este objeto antes de que el método se complete (y la referencia queda fuera del alcance de todos modos).
Tenga en cuenta que rara vez uso esta técnica en realidad, pero vale la pena considerarla cuando se trata de estructuras de datos muy grandes.
Para ampliar la respuesta y el comentario de Yiannis Xanthopoulos y Hot Licks (lo siento, todavía no puedo comentar), puede establecer las opciones de VM como este ejemplo:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
En mi jdk 7 esto liberará la memoria VM no utilizada si más del 30% del montón se vuelve libre después de GC cuando la VM está inactiva. Es probable que necesite ajustar estos parámetros.
Si bien no lo vi enfatizado en el siguiente enlace, tenga en cuenta que algunos recolectores de basura pueden no obedecer estos parámetros y, por defecto, java puede elegir uno de estos para usted, si tiene más de un núcleo (de ahí el argumento UseG1GC anterior) )
Actualización: para java 1.8.0_73 He visto que la JVM ocasionalmente libera pequeñas cantidades con la configuración predeterminada. Parece que solo lo hará si ~ 70% del montón no se usa. No sé si sería más agresivo liberarlo si el sistema operativo tiene poca memoria física.
Si realmente desea asignar y liberar un bloque de memoria, puede hacerlo con ByteBuffers directos. Incluso hay una forma no portátil de liberar la memoria.
Sin embargo, como se ha sugerido, solo porque tiene que liberar memoria en C, no significa que sea una buena idea tener que hacer esto.
Si sientes que realmente tienes un buen caso de uso gratis (), por favor inclúyelo en la pregunta para que podamos ver qué estás haciendo, es muy probable que haya una mejor manera.
Una razón válida para querer liberar memoria de cualquier programa (java o no) es hacer que haya más memoria disponible para otros programas en el nivel del sistema operativo. Si mi aplicación Java está usando 250 MB, es posible que desee forzarlo a reducir a 1 MB y poner los 249 MB disponibles para otras aplicaciones.
* "Por ejemplo, supongamos que declaró una Lista al principio de un método que creció en tamaño para ser muy grande, pero solo fue necesario hasta la mitad del método. En este punto, podría establecer la referencia de Lista en nulo para permitir que el recolector de basura recupere potencialmente este objeto antes de que el método se complete (y la referencia queda fuera del alcance de todos modos) ". *
Esto es correcto, pero esta solución puede no ser generalizable. Al establecer una referencia de objeto de lista a nulo, hará que la memoria esté disponible para la recolección de elementos no utilizados, esto solo es cierto para un objeto de lista de tipos primitivos. Si el objeto List contiene en su lugar tipos de referencia, al establecer List object = null no se eliminarán los valores de ninguno de los tipos de referencia que figuran en la lista. En este caso, establecer List object = null huérfano los tipos de referencia contenidos cuyos objetos no estarán disponibles para la recolección de basura a menos que el algoritmo de recolección de basura sea lo suficientemente inteligente como para determinar que los objetos se han quedado huérfanos.
System.gc();
Ejecuta el recolector de basura.
Llamar al método gc sugiere que la Máquina Virtual Java gasta esfuerzos para reciclar objetos no utilizados a fin de que la memoria que ocupan actualmente esté disponible para su reutilización rápida. Cuando el control vuelve de la llamada al método, la Máquina Virtual Java ha hecho un gran esfuerzo para reclamar espacio de todos los objetos descartados.
No recomendado.
Editar: escribí la respuesta original en 2009. Ahora es 2015.
Los recolectores de basura han mejorado constantemente en los ~ 20 años que Java ha existido. En este punto, si está llamando manualmente al recolector de basura, es posible que desee considerar otros enfoques:
- Si está forzando GC en un número limitado de máquinas, puede valer la pena tener un punto de balanceador de carga alejado de la máquina actual, esperando que termine de servir a los clientes conectados, tiempo de espera después de un período para colgar las conexiones, y luego difícilmente -restart la JVM. Esta es una solución terrible, pero si está mirando System.gc (), los reinicios forzados pueden ser una posibilidad provisional.
- Considere usar un recolector de basura diferente. Por ejemplo, el (nuevo en los últimos seis años) G1 collector es un modelo de baja pausa; usa más CPU en general, pero ¿es mejor nunca forzar una ejecución de parada dura? Dado que las CPU del servidor ahora casi todos tienen núcleos múltiples, esta es una compensación verdaderamente buena para tener disponible.
- Mire sus banderas para ajustar el uso de la memoria. Especialmente en versiones más nuevas de Java, si no tiene tantos objetos en ejecución a largo plazo, considere aumentar el tamaño de newgen en el montón. newgen (joven) es donde se asignan nuevos objetos. Para un servidor web, todo lo creado para una solicitud se coloca aquí, y si este espacio es demasiado pequeño, Java pasará más tiempo actualizando los objetos a la memoria de mayor duración, donde son más caros de matar. (Si newgen es un poco demasiado pequeño, vas a pagarlo). Por ejemplo, en G1:
- XX: G1NewSizePercent (por defecto es 5, probablemente no importe)
- XX: G1MaxNewSizePercent (por defecto es 60, probablemente plantee esto)
- Considere decirle al recolector de basura que no está de acuerdo con una pausa más larga. Esto causará ejecuciones GC más frecuentes, para permitir que el sistema conserve el resto de sus restricciones. En G1:
- XX: MaxGCPauseMillis (predeterminado a 200)