JavaRush /Blog Java /Random-ES /Pausa para el café #210. Todos los tipos de recolectores ...

Pausa para el café #210. Todos los tipos de recolectores de basura en Java que debes conocer

Publicado en el grupo Random-ES
Fuente: Hackernoon A través de esta publicación, conocerá las fortalezas y debilidades de cada tipo de recolector de basura utilizado en el desarrollo de Java. Pausa para el café #210.  Todos los tipos de recolectores de basura en Java que debes conocer - 1La pregunta sobre Garbage Collector (GC) se puede escuchar en casi todas las entrevistas. Así que decidí recopilar toda la información necesaria sobre ellos utilizando mi principio favorito: breve y sencillo. Primero, comencemos con el propósito de CG y por qué necesitamos múltiples tipos de recolectores de basura. En lenguajes como C, necesitamos almacenar información de objetos en la memoria y escribir una gran cantidad de código repetitivo para liberar esa memoria. Por supuesto, las pérdidas de memoria son comunes en este tipo de programas. Java resuelve el problema de las pérdidas de memoria mediante un recolector de basura. Y usted, como desarrollador, debe saber qué recolector de basura es mejor utilizar. Mucho depende de dónde y cómo se ejecuta su programa. Puede ejecutarse en hardware débil o con una gran cantidad de objetos, o su programa debe ser muy rápido. Según estas condiciones, debe ajustar su recolector de basura para lograr el rendimiento deseado. Vamos a empezar.

Cómo maneja la JVM la memoria

La máquina virtual Java (JVM) divide la memoria en dos áreas: el montón, que almacena datos de la aplicación, y el no montón, que almacena el código del programa y otros datos. Dirijamos nuestra atención al área del montón. Aquí es donde nuestro programa crea nuevos objetos. Todos los recolectores de basura se basan en el hecho de que muchos programas utilizan objetos efímeros. Es decir, estos objetos fueron creados, luego cumplieron su función y ya no son necesarios. La mayoría de estos objetos. Pero algunos objetos viven mucho más tiempo, tal vez incluso durante toda la duración del programa. De aquí surge la idea de dividir los objetos en generaciones jóvenes y mayores. Y debemos controlar muy a menudo a la generación más joven. El caso es que los procesos de recogida de basura se dividen en limpieza menor, que afecta únicamente a la generación más joven, y limpieza completa, que puede afectar a ambas generaciones. Recuerde que el recolector de basura es un programa. Y requiere tiempo y recursos de su computadora para funcionar. Lo que también afecta a nuestra aplicación. ¿Cómo afecta? Por ejemplo, para realizar la recolección de basura, la JVM pausa nuestra aplicación. Esto se llama pausa Stop-The-World (STW). Durante este tiempo, se suspenden todos los subprocesos de la aplicación. Pero la aplicación interna lo ignora por completo. Para la aplicación, el tiempo fluye uniformemente. ¿Por qué es tan malo? Imagínese, está escribiendo algún tipo de solicitud de intercambio o una solicitud para el piloto automático de un avión. Su aplicación podría entrar en suspensión por un segundo y la naturaleza de su problema podría cambiar dramáticamente. Es decir, la pausa es un parámetro importante para todo recolector de basura. La siguiente propiedad fundamental del recolector de basura es el tiempo total dedicado a recolectar basura en relación con el tiempo total de ejecución del programa. ¿Qué significa esto y por qué es tan importante? En lugar de una gran fase de "Detener el mundo", podemos elegir un algoritmo con muchas pequeñas pausas. Es preferible hacer pequeños descansos, pero nada sale gratis. En este caso pagamos aumentando el tiempo total de ejecución del programa. Y esto también debemos tenerlo en cuenta. El siguiente parámetro es la cantidad de recursos de hardware. Cada recopilador necesita memoria para almacenar información del objeto y un procesador para realizar la limpieza. El último parámetro es la velocidad. La eficiencia de la recolección de basura se refiere a la rapidez y eficiencia con la que el recolector de basura (GC) recupera la memoria que un programa ya no utiliza. Todos estos parámetros influyen en el algoritmo, que puede liberar memoria lo más rápido posible con un consumo mínimo de recursos. Echemos un vistazo a los recolectores de basura que tenemos a nuestra disposición. Para la entrevista necesitas conocer los primeros cinco. Los otros dos son mucho más difíciles.

GC en serie

Serial GC es el recolector de basura de la máquina virtual Java y se ha utilizado desde el comienzo de Java. Es útil para programas con un montón pequeño y que se ejecutan en máquinas menos potentes. Este recolector de basura divide el montón en regiones, que incluyen Eden y Survivor. La región de Eden es el grupo desde el cual se asigna inicialmente la memoria para la mayoría de los objetos. Survivor es un grupo que contiene objetos que sobrevivieron a la recolección de basura en la región de Eden. A medida que el montón se llena, los objetos se mueven entre las regiones de Eden y Survivor. La JVM monitorea constantemente el movimiento de objetos hacia las regiones Survivor y selecciona un umbral apropiado para el número de dichos movimientos, después del cual los objetos se mueven a la región Tenured. Cuando no hay suficiente espacio en la región Tenured, se hace cargo de la recolección de basura completa, trabajando en objetos de ambas generaciones. La principal ventaja de este recolector de basura es su bajo requerimiento de recursos, por lo que un procesador de bajo consumo es suficiente para realizar la recolección. La principal desventaja de Serial GC son las largas pausas durante la recolección de basura, especialmente cuando se trata de grandes cantidades de datos.

CG paralelo

Un recolector de basura paralelo (Parallel CG) es similar a un constructor secuencial. Incluye el procesamiento paralelo de algunas tareas y la capacidad de ajustar automáticamente la configuración de rendimiento. Parallel GC es un recolector de basura de máquina virtual Java basado en las ideas de Serial GC, pero con mayor paralelismo e inteligencia. Si la computadora tiene más de un núcleo de procesador, la versión anterior de JVM selecciona automáticamente GC paralelo. El montón aquí está dividido en las mismas regiones que en Serial GC: Eden, Survivor 0, Survivor 1 y Old Gen (Tenured). Sin embargo, varios subprocesos participan en la recolección de basura en paralelo y el recolector puede ajustarse a los parámetros de rendimiento requeridos. Cada hilo recopilador tiene un área de memoria que debe borrarse. Parallel GC también tiene configuraciones destinadas a lograr la eficiencia de recolección de basura requerida. El recolector utiliza estadísticas de recolecciones de basura anteriores para ajustar la configuración de rendimiento para recolecciones futuras. Parallel GC proporciona ajuste automático de los parámetros de rendimiento y tiempos de pausa de compilación más bajos, pero existe un pequeño inconveniente en forma de cierta fragmentación de la memoria. Es adecuado para la mayoría de las aplicaciones, pero para programas más complejos es mejor elegir implementaciones de recolector de basura más avanzadas. Ventajas: Más rápido que Serial GC en muchos casos. Tiene buena velocidad. Contras: Consume más recursos y las pausas pueden ser bastante largas, pero podemos ajustar la duración máxima de la pausa de Stop-The-World.

Barrido de marcas simultáneo

El recolector de basura Concurrent Mark Sweep (CMS) tiene como objetivo reducir la duración máxima de la pausa ejecutando algunas tareas de recolección de basura al mismo tiempo que los subprocesos de la aplicación. Este recolector de basura es adecuado para gestionar grandes cantidades de datos en la memoria. Concurrent Mark Sweep (CMS) es una alternativa a Parallel GC en la máquina virtual Java (JVM). Está destinado a aplicaciones que requieren acceso a múltiples núcleos de procesador y son sensibles a las pausas de Stop-The-World. El CMS realiza pasos de recolección de basura en paralelo con el programa principal, lo que le permite ejecutarse sin detenerse. Utiliza la misma organización de memoria que los recopiladores Serial y Parallel, pero no espera a que se llene el área Tenured antes de ejecutar la purga de la generación anterior. En cambio, se ejecuta en segundo plano e intenta mantener compacta la región titular. Concurrent Mark Sweep comienza con una fase de marcado inicial que detiene brevemente los subprocesos principales de la aplicación y marca todos los objetos accesibles desde la raíz. Luego, los subprocesos principales de la aplicación se reanudan y el CMS comienza a buscar todos los objetos activos a los que se puede acceder mediante enlaces desde los objetos raíz marcados. Después de marcar todos los objetos vivos, el coleccionista borra la memoria de los objetos muertos en varios hilos paralelos. Uno de los beneficios de un CMS es su enfoque en minimizar el tiempo de inactividad, lo cual es fundamental para muchas aplicaciones. Sin embargo, requiere sacrificios en términos de recursos de CPU y ancho de banda general. Además, el CMS no comprime los objetos de la generación anterior, lo que provoca fragmentación. Las pausas prolongadas debido a posibles fallas en el modo paralelo pueden ser una sorpresa desagradable (aunque no ocurren con frecuencia). Si hay suficiente memoria, el CMS puede evitar este tipo de pausas. Ventajas: Rápido. Tiene pequeñas pausas de Stop-The-World. Contras: consume más memoria; si no hay suficiente memoria, algunas pausas pueden ser largas. No muy bueno si la aplicación crea muchos objetos.

Basura primero

Garbage-First (G1) se considera una alternativa a un CMS, especialmente para aplicaciones de servidor que se ejecutan en servidores multiprocesador y gestionan grandes conjuntos de datos. El recolector de basura G1 convierte la memoria en múltiples regiones del mismo tamaño, con la excepción de las regiones enormes (que se crean fusionando regiones regulares para acomodar objetos masivos). Las regiones no tienen que estar organizadas en una fila y pueden cambiar su afiliación generacional. Periódicamente se realizan pequeñas purgas para la generación más joven y se mueven objetos a regiones de Survivor o se actualizan a la generación anterior y se transfieren a Tenured. La limpieza se realiza únicamente en aquellas regiones donde es necesario evitar exceder el tiempo deseado. El propio recolector predice y selecciona las regiones con mayor cantidad de basura para su limpieza. Los barridos completos utilizan un bucle de marcado para crear una lista de objetos activos que se ejecuta en paralelo con la aplicación principal. Después del ciclo de marcado, G1 pasa a ejecutar purgas mixtas, que agregan regiones de generaciones más antiguas al conjunto de regiones de generaciones más jóvenes que se van a purgar. Se considera que el recolector de basura G1 es más preciso que el recolector CMS a la hora de predecir el tamaño de las pausas y distribuye mejor la recolección de basura a lo largo del tiempo para evitar tiempos de inactividad prolongados de las aplicaciones, especialmente con tamaños de montón grandes. Tampoco fragmenta la memoria como el recopilador CMS. Sin embargo, el recopilador G1 requiere más recursos de CPU para ejecutarse en paralelo con el programa principal, lo que reduce el rendimiento de la aplicación. Ventajas: Funciona mejor que CMS. Tiene pausas más cortas. Contras: Consume más recursos de CPU. También consume más memoria si tenemos muchos objetos bastante grandes (más de 500 KB) porque los coloca en una región (1-32 MB).

Épsilon GC

Epsilon GC está diseñado para situaciones en las que no se requiere recolección de basura. No realiza recolección de basura, pero utiliza TLAB (búferes de asignación local de subprocesos) para asignar nuevos objetos: pequeños búferes de memoria solicitados por subprocesos individuales del montón. Los objetos enormes que no caben en el búfer solicitan bloques de memoria específicamente para ellos mismos. Cuando Epsilon GC se queda sin recursos, se genera un OutOfMemoryError y el proceso finaliza. Los beneficios de Epsilon GC incluyen menores requisitos de recursos y una asignación de memoria más rápida para aplicaciones que crean todos los objetos que necesitan al inicio o ejecutan aplicaciones de corta duración que no utilizan toda la memoria asignada. Epsilon GC también puede ayudar a analizar los requisitos de recursos que otros recolectores de basura agregan a su aplicación. Ventajas: Muy rápido. Desventajas: No borra objetos :) Los siguientes dos coleccionistas son los más avanzados de su tipo, pero también los más complejos. Por tanto, los consideraremos brevemente.

ZGC

ZGC puede mantener una latencia inferior a un milisegundo incluso cuando se trata de grandes cantidades de datos. ZGC es un recolector de basura desarrollado por Oracle para Java que está diseñado para proporcionar un alto rendimiento y baja latencia al procesar grandes montones (hasta 16 TB). ZGC se basa en principios de memoria virtual y utiliza marcas de diferentes colores para rastrear el estado de los objetos durante la recolección de basura. Ventajas: Las pausas son de menos de un milisegundo, incluso en montones grandes, lo cual es muy útil para aplicaciones que requieren tiempos cortos de procesamiento de consultas. Funciona con montones muy grandes con buen rendimiento. ZGC puede comprimir la memoria del montón durante la recolección de basura. Desventajas: uso elevado de CPU y requisitos de rendimiento importantes, que pueden ralentizar los tiempos de inicio de las aplicaciones.

Shenandoah G.C.

Shenandoah GC es otro recolector de basura con pausas breves independientemente del tamaño del montón. Este recolector de basura está desarrollado por Red Hat. Está diseñado para minimizar el tiempo que una aplicación dedica a la recolección de basura. Al igual que ZGC, es un recopilador paralelo, lo que significa que se ejecuta mientras se ejecuta la aplicación, minimizando las pausas. Shenandoah GC utiliza "punteros de reenvío" para mover objetos durante la recolección de basura. También cuenta con una técnica llamada “eliminación de barrera de carga” para mejorar el rendimiento. Ventajas: Shenandoah GC puede lograr tiempos de pausa cortos, a menudo menos de 10 ms, incluso para montones masivos. Buen rendimiento. Contras: alta carga del procesador y dificultad para trabajar bajo cargas pesadas.

Conclusión

Los recolectores de basura son una de las tareas más difíciles en programación. Constantemente se llevan a cabo nuevos desarrollos en esta dirección. Si bien es raro que los programadores modifiquen el GC, aún necesita tener al menos un conocimiento básico de cómo funciona su herramienta de recolección de basura.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION