¿Hay alguna forma de liberar memoria en Java, similar a la free()
función de C ? ¿O establecer el objeto en nulo y confiar en GC es la única opción?
¿Hay alguna forma de liberar memoria en Java, similar a la free()
función de C ? ¿O establecer el objeto en nulo y confiar en GC es la única opción?
Respuestas:
Java usa memoria administrada, por lo que la única forma en que puede asignar memoria es mediante el new
operador, y la única forma en que puede desasignar la memoria es confiando 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 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 hace un esfuerzo para reciclar objetos no utilizados con el fin de hacer que la memoria que ocupan actualmente esté disponible para su reutilización rápida. Cuando el control regresa de la llamada al método, Java Virtual Machine ha hecho un gran esfuerzo para reclamar espacio de todos los objetos descartados.
System.gc()
completo.
Nadie parece haber mencionado explícitamente el establecimiento de referencias a objetos null
, lo cual es una técnica legítima para "liberar" memoria que quizás desee considerar.
Por ejemplo, supongamos que declaró List<String>
al principio de un método que creció en tamaño para ser muy grande, pero que solo fue necesario hasta la mitad del método. En este punto, podría establecer la referencia de Lista null
para permitir que el recolector de basura pueda reclamar potencialmente este objeto antes de que se complete el método (y la referencia queda fuera de alcance de todos modos).
Tenga en cuenta que rara vez uso esta técnica en realidad, pero vale la pena considerarla al tratar con estructuras de datos muy grandes.
System.gc();
Ejecuta el recolector de basura.
Llamar al método gc sugiere que la máquina virtual Java hace un esfuerzo para reciclar objetos no utilizados con el fin de hacer que la memoria que ocupan actualmente esté disponible para su reutilización rápida. Cuando el control regresa 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:
* "Personalmente, confío en las variables de anulación como 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 nula) la matriz en sí".
Esto es innecesario La forma en que funciona el GC de Java es que encuentra objetos que no tienen referencia a ellos, por lo que si tengo un Object x con una referencia (= variable) a que apunta a él, el GC no lo eliminará, porque hay una referencia a ese objeto:
a -> x
Si nulo a, esto sucede:
a -> null
x
Entonces ahora x no tiene una referencia apuntando a él y será eliminado. Lo mismo sucede cuando configuras una referencia a un objeto diferente a x.
Entonces, si tiene una matriz arr que hace referencia a objetos x, y y z y una variable a que hace referencia a la matriz, se ve así:
a -> arr -> x
-> y
-> z
Si nulo a, esto sucede:
a -> null
arr -> x
-> y
-> z
Por lo tanto, el GC considera que arr no tiene un conjunto de referencias y lo elimina, lo que le da esta estructura:
a -> null
x
y
z
Ahora el GC encuentra x, y y z y también los elimina. Anular cada referencia en la matriz no mejorará nada, solo usará el tiempo y el espacio de la CPU en el código (dicho eso, no dolerá más que eso. El GC aún podrá funcionar de la manera que debería )
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 utiliza 250 MB, es posible que desee forzarla a 1 MB y hacer que los 249 MB estén disponibles para otras aplicaciones.
Para ampliar la respuesta y el comentario de Yiannis Xanthopoulos y Hot Licks (lo siento, ¡no puedo comentar aún!), Puede configurar las opciones de VM como este ejemplo:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
En mi jdk 7, esto liberará memoria de VM no utilizada si más del 30% del montón se libera después de GC cuando la VM está inactiva. Probablemente necesitará 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, de forma predeterminada, Java puede elegir uno de estos para usted, en caso de que tenga 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 lanza pequeñas cantidades con la configuración predeterminada. Parece que solo lo hace si ~ 70% del montón no se usa, sin embargo ... no sé si sería más agresivo la liberación si el sistema operativo tuviera poca memoria física.
He hecho experimentos al respecto.
Es cierto que System.gc();
solo sugiere ejecutar el recolector de basura.
Pero llamar System.gc();
después de establecer todas las referencias a null
, mejorará el rendimiento y la ocupación de la memoria.
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 tenga que liberar memoria en C, no significa que sea una buena idea tener que hacer esto.
Si cree que realmente tiene un buen caso de uso gratis (), inclúyalo en la pregunta para que podamos ver lo que está tratando de hacer, es muy probable que haya una mejor manera.
Completamente de javacoffeebreak.com/faq/faq0012.html
Un subproceso de baja prioridad se encarga 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 se preocupe, ¡no eliminará sus objetos!
Cuando no hay referencias a un objeto, se convierte en un juego justo para el recolector de basura. En lugar de llamar a alguna rutina (como gratuita en C ++), simplemente asigna todas las referencias al objeto como nulas, 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 que el recolector de basura comience a reclamar espacio, en lugar de permitir que lo haga como un subproceso de baja prioridad. Para hacer esto, agregue lo siguiente a su código
System.gc();
El recolector de basura intentará recuperar espacio libre, y su aplicación puede continuar ejecutándose, con la mayor cantidad de memoria recuperada posible (pueden aplicarse problemas de fragmentación de memoria en ciertas plataformas).
En mi caso, dado que mi código Java está destinado a ser portado a otros idiomas en un futuro próximo (principalmente C ++), al menos quiero pagar el servicio de labio para liberar la memoria correctamente, por lo que ayuda al proceso de portabilidad más adelante.
Personalmente, confío en las variables de anulación como marcador de posición para la eliminación adecuada en el futuro. Por ejemplo, me tomo el tiempo de anular todos los elementos de una matriz antes de eliminar (hacer nula) la matriz en sí.
Pero mi caso es muy particular, y sé que estoy tomando éxitos de rendimiento cuando hago esto.
* "Por ejemplo, supongamos que declaró una Lista al comienzo de un método que creció en tamaño para ser muy grande, pero que solo se requería hasta la mitad del método. En este punto, podría establecer la referencia de Lista como nula para permitir que el recolector de basura reclame potencialmente este objeto antes de que se complete el método (y la referencia queda fuera de alcance de todos modos) ". * *
Esto es correcto, pero esta solución puede no ser generalizable. Si bien establecer una referencia de objeto List a nulo-hará que la memoria esté disponible para la recolección de basura, esto solo es cierto para un objeto List de tipos primitivos. Si el objeto Lista contiene tipos de referencia, establecer el objeto Lista = nulo no desreferenciará -cualquier- de los tipos de referencia contenidos -en- la lista. En este caso, establecer el objeto Lista = nulo dejará huérfanos 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 han quedado huérfanos.
Althrough java proporciona recolección de basura automática, a veces querrá 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 yfreeMemory()
La recomendación de JAVA es asignar a nulo
De https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
Asignar explícitamente un valor nulo a las variables que ya no son necesarias ayuda al recolector de basura a identificar las partes de la memoria que pueden recuperarse de forma segura. Aunque Java proporciona administración de memoria, no evita pérdidas de memoria o el uso de cantidades excesivas de memoria.
Una aplicación puede provocar pérdidas de memoria al no liberar referencias de objetos. Hacerlo evita que el recolector de basura de Java reclame esos objetos y da como resultado el uso de cantidades cada vez mayores de memoria. Anular explícitamente las referencias a variables después de su uso permite al recolector de basura recuperar memoria.
Una forma de detectar pérdidas 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 estable mostrará una memoria de montón activa estable después de la recolección de basura.