Sé que la recolección de basura está automatizada en Java. Pero entendí que si llama System.gc()
a su código, la JVM puede o no decidir realizar la recolección de basura en ese momento. ¿Cómo funciona esto precisamente? ¿Sobre qué base / parámetros exactamente la JVM decide hacer (o no hacer) un GC cuando ve System.gc()
?
¿Hay ejemplos en cuyo caso es una buena idea poner esto en su código?
java
garbage-collection
Miguel
fuente
fuente
Respuestas:
En la práctica, suele decidir hacer una recolección de basura. La respuesta varía dependiendo de muchos factores, como en qué JVM se está ejecutando, en qué modo se encuentra y qué algoritmo de recolección de basura está utilizando.
No dependería de eso en tu código. Si la JVM está a punto de lanzar un OutOfMemoryError, llamar a System.gc () no lo detendrá, porque el recolector de basura intentará liberar todo lo que pueda antes de llegar a ese extremo. La única vez que lo he visto en la práctica es en IDE, donde está adjunto a un botón en el que un usuario puede hacer clic, pero incluso allí no es muy útil.
fuente
System.gc()
en una pantalla de carga para un videojuego. En ese momento, realmente no me importaría si la llamada despejó todo lo posible, o no hizo nada en absoluto. Sin embargo, preferiría que "se esfuerce en reciclar los objetos no utilizados" durante la pantalla de carga, en lugar de durante el juego.El único ejemplo en el que se me ocurre dónde tiene sentido llamar a System.gc () es cuando se crea un perfil de una aplicación para buscar posibles fugas de memoria. Creo que los perfiladores llaman a este método justo antes de tomar una instantánea de la memoria.
fuente
La especificación del lenguaje Java no garantiza que la JVM iniciará un GC cuando llame
System.gc()
. Esta es la razón de esto "puede que decida o no hacer un GC en ese momento".Ahora, si observa el código fuente de OpenJDK , que es la columna vertebral de Oracle JVM, verá que una llamada a
System.gc()
inicia un ciclo de GC. Si usa otra JVM, como J9, debe verificar su documentación para encontrar la respuesta. Por ejemplo, la JVM de Azul tiene un recolector de basura que se ejecuta continuamente, por lo que una llamada aSystem.gc()
no hará nada.Alguna otra respuesta menciona el inicio de un GC en JConsole o VisualVM. Básicamente, estas herramientas realizan una llamada remota a
System.gc()
.Por lo general, no desea iniciar un ciclo de recolección de basura desde su código, ya que interfiere con la semántica de su aplicación. Su aplicación hace algunas cosas comerciales, la JVM se encarga de la administración de la memoria. Debe mantener esas preocupaciones separadas (no haga que su aplicación administre la memoria, céntrese en los negocios).
Sin embargo, hay pocos casos en los que una llamada a
System.gc()
pueda ser comprensible. Considere, por ejemplo, los microbenchmarks. Nadie quiere que suceda un ciclo de GC en medio de un microbenchmark. Por lo tanto, puede activar un ciclo de GC entre cada medición para asegurarse de que cada medición comience con un montón vacío.fuente
No tienes control sobre GC en Java: la VM decide. Nunca me he encontrado con un caso en el que
System.gc()
sea necesario . Dado que unaSystem.gc()
llamada simplemente SUGIERE que la VM haga una recolección de basura y también hace una recolección de basura COMPLETA (generaciones antiguas y nuevas en un montón multigeneracional), entonces en realidad puede causar que se consuman MÁS ciclos de CPU de lo necesario.En algunos casos, puede tener sentido sugerirle a la máquina virtual que haga una recopilación completa AHORA, ya que puede saber que la aplicación estará inactiva durante los próximos minutos antes de que ocurra el levantamiento de objetos pesados. Por ejemplo, justo después de la inicialización de una gran cantidad de objetos temporales durante el inicio de la aplicación (es decir, acabo de almacenar en caché una TONELADA de información y sé que no obtendré mucha actividad durante un minuto más o menos). Piense en un IDE como eclipse que se inicia; hace mucho para inicializar, por lo que quizás inmediatamente después de la inicialización tenga sentido hacer un gc completo en ese punto.
fuente
Debe tener mucho cuidado si llama
System.gc()
. Llamarlo puede agregar problemas de rendimiento innecesarios a su aplicación y no se garantiza que realmente realice una recopilación. De hecho, es posible deshabilitar explícitamente aSystem.gc()
través del argumento java-XX:+DisableExplicitGC
.Recomiendo encarecidamente leer los documentos disponibles en Java HotSpot Garbage Collection para obtener más detalles sobre la recolección de basura.
fuente
System.gc()
es implementado por la máquina virtual, y lo que hace es específico de la implementación. El implementador podría simplemente regresar y no hacer nada, por ejemplo.En cuanto a cuándo emitir una recopilación manual, el único momento en el que puede querer hacer esto es cuando abandona una colección grande que contiene un montón de colecciones más pequeñas,
Map<String,<LinkedList>>
por ejemplo, y desea probar y tomar el golpe de perforación entonces y allí, pero en su mayor parte, no debe preocuparse por eso. La CG sabe mejor que tú, lamentablemente, la mayor parte del tiempo.fuente
Si usa búferes de memoria directa, la JVM no ejecuta el GC por usted, incluso si se está quedando sin memoria directa.
Si llama
ByteBuffer.allocateDirect()
y obtiene un OutOfMemoryError, puede encontrar que esta llamada está bien después de activar un GC manualmente.fuente
Cleaners
que utiliza memoria directa. es decir, el subproceso finalizador no lo libera, ya que puede ser demasiado lento. Aun así, es posible obtener un OOME si está creando regiones de memoria directa particularmente rápido. La solución es no hacer eso y reutilizar sus regiones de memoria directa donde pueda.La mayoría de las JVM iniciarán un GC (según el modificador -XX: DiableExplicitGC y -XX: + ExplicitGCInvokesConcurrent). Pero la especificación está menos bien definida para permitir mejores implementaciones más adelante.
La especificación necesita aclaración: Error # 6668279: (spec) System.gc () debería indicar que no recomendamos su uso y no garantizamos el comportamiento
Internamente, RMI y NIO utilizan el método gc, y requieren ejecución síncrona, que: esto está actualmente en discusión:
Error # 5025281: Permitir que System.gc () active colecciones completas concurrentes (no para detener el mundo)
fuente
Garbage Collection
es buenoJava
si estamos ejecutando Software codificado en Java en Desktop / laptop / server. Puede llamarSystem.gc()
oRuntime.getRuntime().gc()
entrarJava
.Solo tenga en cuenta que ninguna de esas llamadas está garantizada para hacer algo. Son solo una sugerencia para que jvm ejecute el recolector de basura. Depende de la JVM si ejecuta el GC o no. Entonces, respuesta corta: no sabemos cuándo se ejecuta. Respuesta más larga: JVM ejecutaría gc si tuviera tiempo para eso.
Creo que lo mismo se aplica a Android. Sin embargo, esto podría ralentizar su sistema.
fuente
Normalmente, la máquina virtual haría una recolección de basura automáticamente antes de lanzar una excepción OutOfMemoryException, por lo que agregar una llamada explícita no debería ayudar, excepto en que tal vez mueva el impacto de rendimiento a un momento anterior en el tiempo.
Sin embargo, creo que encontré un caso en el que podría ser relevante. Sin embargo, no estoy seguro, ya que todavía tengo que probar si tiene algún efecto:
Cuando asigna en memoria un archivo, creo que la llamada map () arroja una IOException cuando no hay disponible un bloque de memoria lo suficientemente grande. Una recolección de basura justo antes del archivo map () podría ayudar a prevenir eso, creo. ¿Qué piensas?
fuente
nunca podemos forzar la recolección de basura. System.gc solo sugiere vm para la recolección de basura, sin embargo, nadie sabe realmente a qué hora se ejecuta el mecanismo, esto es como lo establecen las especificaciones JSR.
fuente
Hay mucho que decir al tomarse el tiempo para probar las distintas configuraciones de recolección de basura, pero como se mencionó anteriormente, generalmente no es útil hacerlo.
Actualmente estoy trabajando en un proyecto que involucra un entorno con memoria limitada y una cantidad relativamente grande de datos; hay algunos datos grandes que llevan mi entorno al límite, y aunque pude reducir el uso de la memoria, que en teoría debería funcionar bien, todavía obtendría errores de espacio de pila --- las opciones detalladas de GC me mostraron que estaba tratando de recolectar basura, pero fue en vano. En el depurador, podría ejecutar System.gc () y seguro que habría "mucha" memoria disponible ... no mucha más, pero suficiente.
En consecuencia, la única vez que mi aplicación llama a System.gc () es cuando está a punto de ingresar el segmento de código donde se asignarán los grandes búferes necesarios para procesar los datos, y una prueba en la memoria libre disponible indica que no estoy garantizado para tenerlo. En particular, estoy viendo un entorno de 1 GB donde al menos 300 MB están ocupados por datos estáticos, y la mayor parte de los datos no estáticos están relacionados con la ejecución, excepto cuando los datos que se procesan tienen al menos 100-200 MB en la fuente. Todo es parte de un proceso de conversión automática de datos, por lo que todos los datos existen durante períodos de tiempo relativamente cortos a largo plazo.
Desafortunadamente, aunque se dispone de información sobre las diversas opciones para ajustar el recolector de basura, parece en gran medida un proceso experimental y los detalles de nivel inferior necesarios para comprender cómo manejar estas situaciones específicas no se obtienen fácilmente.
Dicho todo esto, a pesar de que estoy usando System.gc (), seguí sintonizando el uso de parámetros de línea de comando y logré mejorar el tiempo de procesamiento general de mi aplicación en una cantidad relativamente significativa, a pesar de no poder superar el obstáculo que plantea trabajar con los bloques de datos más grandes. Dicho esto, System.gc () es una herramienta ... una herramienta muy poco confiable, y si no tiene cuidado con la forma en que la usa, deseará que no funcione la mayoría de las veces.
fuente
Si desea saber si
System.gc()
se llama, puede recibir una notificación con la nueva actualización 4 de Java 7 cuando la JVM realice la recolección de basura.Sin embargo, no estoy 100% seguro de que la clase GarbageCollectorMXBean se haya introducido en la actualización 4 de Java 7, porque no pude encontrarla en las notas de la versión, pero encontré la información en el sitio javaperformancetuning .com
fuente
No puedo pensar en un ejemplo específico cuando sea bueno ejecutar GC explícito.
En general, ejecutar GC explícito en realidad puede causar más daño que bien, porque un GC explícito activará una colección completa, lo que lleva mucho más tiempo a medida que pasa por cada objeto. Si este gc explícito termina siendo llamado repetidamente, podría conducir fácilmente a una aplicación lenta ya que se dedica mucho tiempo a ejecutar GC completos.
Alternativamente, si revisa el montón con un analizador de montón y sospecha que un componente de la biblioteca está llamando a GC explícitos, puede desactivarlo agregando: gc = -XX: + DisableExplicitGC a los parámetros de JVM.
fuente
De acuerdo con Thinking in Java por Bruce Eckel, un caso de uso para la llamada explícita System.gc () es cuando desea forzar la finalización, es decir, la llamada para finalizar el método.
fuente
mientras system.gc funciona, detendrá el mundo: todas las respuestas se detienen para que el recolector de basura pueda escanear cada objeto para verificar si es necesario eliminarlo. si la aplicación es un proyecto web, todas las solicitudes se detienen hasta que finalice gc, y esto hará que su proyecto web no funcione en un monent.
fuente