1. Información general
En este tutorial rápido, mostraremos los conceptos básicos de diferentes implementaciones de recolección de basura (GC) de JVM . Además, descubriremos cómo habilitar un tipo particular de recolección de basura en nuestras aplicaciones.
2. Breve introducción a la recolección de basura
Por el nombre, parece que Garbage Collection se ocupa de encontrar y eliminar la basura de la memoria. Sin embargo, en realidad, Garbage Collection realiza un seguimiento de todos y cada uno de los objetos disponibles en el espacio de almacenamiento dinámico de JVM y elimina los que no se utilizan.
En palabras simples, GC funciona en dos pasos simples conocidos como Marcar y Barrer:
- Marcar: es donde el recolector de basura identifica qué piezas de memoria están en uso y cuáles no.
- Barrido: este paso elimina los objetos identificados durante la fase de "marca"
Ventajas:
- Sin manejo manual de asignación / desasignación de memoria porque el espacio de memoria no utilizado es manejado automáticamente por GC
- Sin gastos generales de manejo del puntero colgante
- Gestión automática de fugas de memoria ( GC por sí solo no puede garantizar la solución completa a prueba de fugas de memoria, sin embargo, se encarga de una buena parte)
Desventajas:
- Dado que JVM tiene que realizar un seguimiento de la creación / eliminación de referencias de objetos, esta actividad requiere más potencia de CPU además de la aplicación original. Puede afectar el rendimiento de las solicitudes que requieren gran cantidad de memoria
- Los programadores no tienen control sobre la programación del tiempo de la CPU dedicado a liberar objetos que ya no son necesarios
- El uso de algunas implementaciones de GC puede hacer que la aplicación se detenga de manera impredecible
- La administración de memoria automatizada no será tan eficiente como la asignación / desasignación de memoria manual adecuada
3. Implementaciones de GC
JVM tiene cuatro tipos de implementaciones de GC :
- Recolector de basura en serie
- Recolector de basura paralelo
- Recolector de basura CMS
- Recolector de basura G1
3.1. Recolector de basura en serie
Esta es la implementación de GC más simple, ya que básicamente funciona con un solo hilo. Como resultado, esta implementación de GC congela todos los subprocesos de la aplicación cuando se ejecuta . Por lo tanto, no es una buena idea usarlo en aplicaciones multiproceso como entornos de servidor.
Sin embargo, hubo una excelente charla de ingenieros de Twitter en QCon 2012 sobre el rendimiento del recolector de basura en serie , que es una buena manera de comprender mejor este recolector.
Serial GC es el recolector de basura preferido para la mayoría de las aplicaciones que no tienen pequeños requisitos de tiempo de pausa y se ejecutan en máquinas de estilo cliente. Para habilitar Serial Garbage Collector , podemos usar el siguiente argumento:
java -XX:+UseSerialGC -jar Application.java
3.2. Recolector de basura paralelo
Es el GC predeterminado de la JVM y, a veces, se denomina recopiladores de rendimiento. A diferencia de Serial Garbage Collector , este utiliza varios subprocesos para administrar el espacio de pila . Pero también congela otros subprocesos de la aplicación mientras realiza GC .
Si usamos este GC , podemos especificar el máximo de subprocesos de recolección de basura y el tiempo de pausa, el rendimiento y la huella (tamaño del montón).
La cantidad de subprocesos del recolector de basura se puede controlar con la opción de línea de comandos -XX: ParallelGCThreads = .
El objetivo de tiempo de pausa máximo (intervalo [en milisegundos] entre dos GC ) se especifica con la opción de línea de comandos -XX: MaxGCPauseMillis = .
El objetivo de rendimiento máximo (medido con respecto al tiempo dedicado a la recolección de basura versus el tiempo dedicado fuera de la recolección de basura) se especifica mediante la opción de línea de comandos -XX: GCTimeRatio =.
La huella de pila máxima (la cantidad de memoria de pila que requiere un programa mientras se ejecuta) se especifica mediante la opción -Xmx.
Para habilitar Parallel Garbage Collector , podemos usar el siguiente argumento:
java -XX:+UseParallelGC -jar Application.java
3.3. Recolector de basura CMS
La implementación de Concurrent Mark Sweep (CMS) utiliza varios subprocesos recolectores de basura para la recolección de basura. Está diseñado para aplicaciones que prefieren pausas de recolección de basura más breves y que pueden permitirse compartir recursos del procesador con el recolector de basura mientras se ejecuta la aplicación.
En pocas palabras, las aplicaciones que utilizan este tipo de GC responden más lentamente en promedio, pero no dejan de responder para realizar la recolección de basura.
Un punto rápido a tener en cuenta aquí es que, dado que este GC es concurrente, una invocación de recolección de basura explícita como el uso de System.gc () mientras el proceso concurrente está funcionando, dará como resultado una falla / interrupción del modo concurrente .
Si más del 98% del tiempo total se dedica a la recolección de elementos no utilizados de CMS y se recupera menos del 2% del montón, el recolector de CMS genera un OutOfMemoryError . Si es necesario, esta función se puede desactivar agregando la opción -XX: -UseGCOverheadLimit a la línea de comando.
Este recopilador también tiene un modo conocido como modo incremental que está en desuso en Java SE 8 y puede eliminarse en una versión principal futura.
Para habilitar el recolector de basura CMS , podemos usar la siguiente bandera:
java -XX:+UseParNewGC -jar Application.java
A partir de Java 9, el recolector de basura CMS ha quedado obsoleto . Por lo tanto, JVM imprime un mensaje de advertencia si intentamos usarlo:
>> java -XX:+UseConcMarkSweepGC --version Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release. java version "9.0.1"
Además, Java 14 eliminó por completo el soporte de CMS:
>> java -XX:+UseConcMarkSweepGC --version OpenJDK 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; support was removed in 14.0 openjdk 14 2020-03-17
3.4. Recolector de basura G1
El recolector de basura G1 (Garbage First) está diseñado para aplicaciones que se ejecutan en máquinas multiprocesador con gran espacio de memoria. Está disponible desde JDK7 Update 4 y en versiones posteriores.
El recopilador G1 reemplazará al recopilador CMS ya que es más eficiente en el rendimiento.
Unlike other collectors, G1 collector partitions the heap into a set of equal-sized heap regions, each a contiguous range of virtual memory. When performing garbage collections, G1 shows a concurrent global marking phase (i.e. phase 1 known as Marking) to determine the liveness of objects throughout the heap.
After the mark phase is completed, G1 knows which regions are mostly empty. It collects in these areas first, which usually yields a significant amount of free space (i.e. phase 2 known as Sweeping). It is why this method of garbage collection is called Garbage-First.
To enable the G1 Garbage Collector, we can use the following argument:
java -XX:+UseG1GC -jar Application.java
3.5. Java 8 Changes
Java 8u20 ha introducido un parámetro más de JVM para reducir el uso innecesario de memoria al crear demasiadas instancias de la misma cadena. Esto optimiza la memoria del montón eliminando los valores de cadena duplicados en una matriz char [] global .
Este parámetro se puede habilitar agregando -XX: + UseStringDeduplication como parámetro de JVM .
4. Conclusión
En este tutorial rápido, echamos un vistazo a las diferentes implementaciones de JVM Garbage Collection y sus casos de uso.
Puede encontrar documentación más detallada aquí.