Recolección de basura Java G1 en producción


91

Dado que Java 7 va a usar la nueva recolección de basura G1 de forma predeterminada, ¿Java podrá manejar un montón de orden de magnitud mayor sin tiempos de pausa de GC supuestamente "devastadores"? ¿Alguien ha implementado G1 en producción? ¿Cuáles fueron sus experiencias?

Para ser justos, la única vez que he visto pausas de GC realmente largas es en montones muy grandes, mucho más de lo que hubiera hecho una estación de trabajo. Para aclarar mi pregunta; ¿G1 abrirá la puerta de entrada a montones de cientos de GB? ¿TUBERCULOSIS?


15
Aunque podría reformularse más específicamente, esta no es una pregunta horrible. Realmente desearía que la gente tuviera que explicarse mejor que "No es una pregunta" al votar para cerrar.
Bill K

No voté para cerrar, pero deseaba que el OP hubiera hecho un trabajo más objetivo al detallar sus quejas con el CG actual. Además, "Java" es un lenguaje mientras que él está hablando de una implementación, y no sé qué significa "implementar G1 en producción", especialmente con el tiempo futuro del resto de la pregunta. Si va a estar en Java 7, ¿seguramente nadie lo ha usado en producción?
Pascal Cuoq

6
@Pascal G1 ha sido una característica experimental disponible en el JDK desde la actualización 14 del JDK 6. Al "implementar G1 en producción", creo que se refería a usarlo realmente, no es tan difícil de imaginar. Y aunque estoy de acuerdo en que G1 es parte de JDK 7, no de Java, una búsqueda de Java 7 en Google devuelve la página de inicio de JDK 7 como su primer resultado, y ambos términos se usan indistintamente. @Benju No confiaría en los resultados obtenidos con G1 en el JDK actual, ya que es experimental, muchas cosas podrían cambiar a partir de ahora hasta el lanzamiento oficial.
teto

2
Parece que el JDK 7, incluida la actualización 1, 2 y 3, no usa el G1 gc de forma predeterminada. Puede comprobarlo con jinfo -flag UseG1GC pid
George

Respuestas:


34

Parece que el objetivo de G1 es tener tiempos de pausa más pequeños, incluso hasta el punto en que tiene la capacidad de especificar un objetivo de tiempo de pausa máximo.

La recolección de basura ya no es un simple trato de "Oye, está lleno, movamos todo de una vez y empecemos de nuevo", es un sistema increíblemente complejo, de múltiples niveles y en segundo plano. Puede hacer gran parte de su mantenimiento en segundo plano sin pausas en absoluto, y también utiliza el conocimiento de los patrones esperados del sistema en tiempo de ejecución para ayudar, como suponer que la mayoría de los objetos mueren justo después de ser creados, etc.

Yo diría que los tiempos de pausa de GC seguirán mejorando, no empeorando, con futuras versiones.

EDITAR:

Al volver a leer, se me ocurrió que uso Java a diario: Eclipse, Azureus y las aplicaciones que desarrollo, y ha pasado MUCHO TIEMPO desde que vi una pausa. No es una pausa significativa, pero me refiero a cualquier pausa.

He visto pausas cuando hago clic con el botón derecho en el explorador de Windows o (ocasionalmente) cuando conecto cierto hardware USB, pero con Java, ninguna en absoluto.

¿GC sigue siendo un problema para alguien?


De acuerdo, la única vez que he visto pausas de GC es cuando las
provoqué

28
Sí, GC sigue siendo un gran problema cuando se empieza a trabajar con montones grandes (> 16 GB), especialmente con las grandes generaciones permanentes.
The Alchemist

2
@ the-alchemist wow, he visto tu comentario de pasada varias veces y me di cuenta de que dijiste 16 GB !! Aunque estoy absolutamente seguro de que tiene razón en que esto puede causar grandes retrasos, quiero comprobar que desactivó TODO el intercambio. En un sistema de memoria grande, cualquier intercambio de Java matará absolutamente su sistema (porque GC es muy antipático). Estoy seguro de que ya lo ha hecho, pero solo quería mencionarlo, porque haría una gran diferencia. Nunca había visto una PC con tanta memoria RAM, ¿cuánto tienes? 32g?
Bill K

8
Sí, los GC son problemáticos para los servicios porque son los que hacen MUY difícil mejorar los límites de TP99.9 (y superiores). Específicamente, los GC de "vieja generación" pueden ser trampas mortales que congelan la JVM (y el servicio) durante varios segundos; y para los servicios que normalmente atienden solicitudes en milisegundos de un solo dígito (o de dos dígitos bajos) esto es problemático. Por lo que vale, esto fue un problema práctico con el almacenamiento de backend utilizado por el servicio Simple Queue de Amazon (no puedo entrar en muchos detalles ya que es interno de AWS).
StaxMan

21
Lo molesto de GC es que Azul inventó hace años un ingenioso algoritmo GC (Azul C4) que puede hacer frente fácilmente a cientos de gigabytes sin tiempos de pausa apreciables haciendo un uso muy inteligente del hardware de memoria del procesador. Pero nadie sabe esto y no se implementará pronto en las principales versiones de Java, ya que necesita algún soporte del sistema operativo. Y los proveedores de sistemas operativos no harán nada hasta que las personas conozcan el algoritmo y ejerzan presión sobre los proveedores de sistemas operativos. Ver azulsystems.com/zing/pgc , managedruntime.org
Hans-Peter Störr

58

Lo he estado probando con una aplicación pesada: 60-70GB asignados al montón, con 20-50GB en uso en cualquier momento. Con este tipo de aplicaciones, es un eufemismo decir que su kilometraje puede variar. Estoy ejecutando JDK 1.6_22 en Linux. Las versiones secundarias son importantes: antes de aproximadamente 1.6_20, había errores en G1 que causaban NullPointerExceptions aleatorias.

Descubrí que es muy bueno para mantenerse dentro del objetivo de pausa que le da la mayor parte del tiempo. El valor predeterminado parece ser una pausa de 100 ms (0,1 segundos), y le he estado diciendo que haga la mitad de eso (-XX: MaxGCPauseMillis = 50). Sin embargo, una vez que tiene poca memoria, entra en pánico y hace una recolección de basura completa. Con 65GB, eso toma entre 30 segundos y 2 minutos. (La cantidad de CPU probablemente no haga una diferencia; probablemente esté limitada por la velocidad del bus).

En comparación con CMS (que no es el servidor GC predeterminado, pero debería serlo para servidores web y otras aplicaciones en tiempo real), las pausas típicas son mucho más predecibles y se pueden hacer mucho más cortas. Hasta ahora estoy teniendo más suerte con CMS por las grandes pausas, pero eso puede ser aleatorio; Los veo solo unas pocas veces cada 24 horas. No estoy seguro de cuál será más apropiado en mi entorno de producción en este momento, pero probablemente G1. Si Oracle sigue sintonizándolo, sospecho que G1 finalmente será el claro ganador.

Si no tiene problemas con los recolectores de basura existentes, no hay razón para considerar G1 en este momento. Si está ejecutando una aplicación de baja latencia, como una aplicación GUI, G1 es probablemente la opción correcta, con MaxGCPauseMillis configurado realmente bajo. Si está ejecutando una aplicación en modo por lotes, G1 no le compra nada.


14

Aunque no he probado G1 en producción, pensé que comentaría que los GC ya son problemáticos para los casos sin montones "enormes". Específicamente, los servicios con solo, digamos, 2 o 4 gigas pueden verse gravemente afectados por GC. Los GC de generación joven generalmente no son problemáticos ya que terminan en milisegundos de un solo dígito (o como mucho en dos dígitos). Pero las colecciones de la vieja generación son mucho más problemáticas ya que toman varios segundos con tamaños de la vieja generación de 1 giga o más.

Ahora: en teoría, CMS puede ayudar mucho allí, ya que puede ejecutar la mayor parte de su funcionamiento al mismo tiempo. Sin embargo, con el tiempo habrá casos en los que no podrá hacer esto y tendrá que recurrir a la colección "stop the world". Y cuando eso suceda (después de, digamos, 1 hora, no a menudo, pero todavía con demasiada frecuencia), bueno, agárrate a tus malditos sombreros. Puede tardar un minuto o más. Esto es especialmente problemático para los servicios que intentan limitar la latencia máxima; en lugar de tomar, digamos, 25 milisegundos para atender una solicitud, ahora toma diez segundos o más. Para agregar daño al insulto, los clientes a menudo agotan la solicitud y lo vuelven a intentar, lo que genera más problemas (también conocido como "tormenta de mierda").

Esta es un área en la que se esperaba que G1 ayudara mucho. Trabajé para una gran empresa que ofrece servicios en la nube para almacenamiento y envío de mensajes; y no pudimos usar CMS ya que, aunque la mayor parte del tiempo funcionaba mejor que las variedades paralelas, tenía estos colapsos. Así que durante una hora las cosas estuvieron bien; y luego las cosas golpearon el ventilador ... y debido a que el servicio se basaba en clústeres, cuando un nodo se metía en problemas, otros generalmente lo seguían (ya que los tiempos de espera inducidos por GC hacen que otros nodos crean que el nodo se ha bloqueado, lo que lleva a redireccionamientos).

No creo que GC sea un gran problema para las aplicaciones, y tal vez incluso los servicios no agrupados se vean afectados con menos frecuencia. Pero cada vez más sistemas están agrupados (especialmente gracias a los almacenes de datos NoSQL) y el tamaño de los montones está creciendo. Los GC de OldGen están superlinealmente relacionados con el tamaño del montón (lo que significa que duplicar el tamaño del montón más que duplica el tiempo del GC, asumiendo que el tamaño del conjunto de datos en vivo también se duplica).


13

El CTO de Azul, Gil Tene, tiene una buena descripción general de los problemas asociados con Garbage Collection y una revisión de varias soluciones en su presentación Understanding Java Garbage Collection y What You Can Do al respecto , y hay detalles adicionales en este artículo: http: // www.infoq.com/articles/azul_gc_in_detail .

El recolector de basura C4 de Azul en nuestra JVM de Zing es paralelo y concurrente, y utiliza el mismo mecanismo de GC tanto para las generaciones nuevas como para las antiguas, trabajando simultáneamente y compactando en ambos casos. Lo más importante es que C4 no tiene un retroceso que pare el mundo. Toda la compactación se realiza al mismo tiempo que la aplicación en ejecución. Tenemos clientes que ejecutan grandes cantidades (cientos de GBytes) con, en el peor de los casos, tiempos de pausa de GC de <10 mseg, y dependiendo de la aplicación, a menudo, menos de 1-2 mseg.

El problema con CMS y G1 es que en algún momento la memoria del montón de Java debe compactarse, y ambos recolectores de basura detienen el mundo / STW (es decir, pausan la aplicación) para realizar la compactación. Entonces, aunque CMS y G1 pueden eliminar las pausas STW, no las eliminan. Sin embargo, el C4 de Azul elimina por completo las pausas STW y es por eso que Zing tiene pausas GC tan bajas incluso para tamaños de montón gigantes.

Y para corregir una afirmación hecha en una respuesta anterior, Zing no requiere ningún cambio en el sistema operativo. Se ejecuta como cualquier otra JVM en distribuciones de Linux sin modificar.


3
Me pregunto cómo el C4 de Azul logró lo que dijo y por qué Sun u Oracle no pueden. ¿Hay algún gran secreto o esto es solo una especie de compensación?
George

5
El C4 de Azul tiene una tecnología única que tiene su origen en los dispositivos informáticos de hardware de Azul (que utilizan procesadores especializados creados para ejecutar aplicaciones Java empresariales) y se ha desarrollado para ejecutarse en servidores x86 normales que ejecutan Linux. Todos los demás recolectores de basura de clase empresarial (ya sea de Oracle o IBM) en algún momento deben hacer pausas para detener el mundo: el atributo único del C4 de Azul es que nunca hace estas pausas problemáticas de STW. Si tiene curiosidad, los inventores del colector C4 publicaron un artículo sobre cómo funciona: dl.acm.org/citation.cfm?id=1064988 .
Scott Sellers

Scott, leí aquí blog.mikemccandless.com/2012/07/… que Azul envía un módulo del kernel que preasigna memoria para el uso de JVM. ¿No es esto cierto? Si es cierto, no es una gran modificación del kernel, pero sigue siendo una modificación.
Dan Pritts

4
George, dos palabras: protegido por patente. Dan, cuando compras Zing, parte de lo que estás pagando es que el personal de soporte lo sintonice para tu aplicación, y eso incluye asignar el uso general de la memoria del sistema. El módulo del kernel en sí mismo evita las escrituras en un bloque de memoria que se está recolectando basura. Esa es la salsa secreta que lo hace "sin pausa": los hilos solo se detienen si intentan escribir en uno de esos bloques, y luego solo el tiempo suficiente para compactar ese bloque.
David Leppik

13

Ya estamos usando G1GC, desde hace casi dos años. Está funcionando muy bien en nuestro sistema de procesamiento de transacciones de misión crítica, y demostró ser un gran soporte para alto rendimiento, bajas pausas, concurrencia y administración optimizada de memoria pesada.

Estamos utilizando la siguiente configuración de JVM:

-server -Xms512m -Xmx3076m -XX:NewRatio=50 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000 -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime

Actualizado

-d64 -server -Xss4m -Xms1024m -Xmx4096m -XX:NewRatio=50 -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:-DisableExplicitGC -XX:+AggressiveOpts -Xnoclassgc -XX:+UseNUMA -XX:+UseFastAccessorMethods -XX:ReservedCodeCacheSize=48m -XX:+UseStringCache -XX:+UseStringDeduplication -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000

5
En Java 8, no es necesario configurar -XX: + UseCompressedOops o -XX: + DoEscapeAnalysis, la cabina está activada de forma predeterminada. Ver: docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
Mirko Ebert

8

El colector G1 reduce el impacto de las colecciones completas. Si tiene una aplicación en la que ya ha reducido la necesidad de recopilaciones completas, el colector de barrido de mapas concurrentes es igual de bueno y, en mi experiencia, tiene tiempos de recopilación menor más cortos.


"Tenga en cuenta que el uso de producción de G1 solo está permitido cuando se ha adquirido un contrato de soporte de Java", groups.google.com/forum/#!topic/javaposse/Vm0a4H-QY54 , ¿es un mito o no?
Christophe Roussy

1
@ChristopheRoussy Ya no sé si esto es cierto (o de hecho tengo pruebas de que alguna vez fue cierto). No requiere las -XX: + UnlockCommercialFeatures, así que sospecho que G1 no requiere una licencia.
Peter Lawrey


5

Recientemente me han trasladado de

CMS a G1GC con heap 4G y procesador de 8 núcleos en servidores con JDK 1.7.45 .

(Se prefiere JDK 1.8.x G1GC a 1.7 pero debido a algunas limitaciones, tengo que ceñirme a la versión 1.7.45)

He configurado los siguientes parámetros clave y he mantenido todos los demás parámetros en los valores predeterminados.

-XX:G1HeapRegionSize=n, XX:MaxGCPauseMillis=m, -XX:ParallelGCThreads=n, 
-XX:ConcGCThreads=n apart from -Xms and -Xmx

Si desea ajustar estos parámetros, eche un vistazo a este artículo de Oracle .

Observaciones clave:

  1. El uso de memoria es consistente con G1GC a diferencia de los altos y bajos con CMS
  2. El tiempo máximo de pausa de GC es menor en comparación con CMS
  3. El tiempo dedicado a la recolección de basura es un poco alto en G1GC en comparación con CMS.
  4. El número de colecciones importantes es casi insignificante en comparación con CMS
  5. El número de colecciones menores está en un extremo superior en comparación con CMS

Pero todavía estoy feliz de que el tiempo de pausa de Max GC sea menor que el de CMS. Establecí el tiempo de pausa Max GC en 1,5 segundos y este valor aún no se ha cruzado.

Pregunta SE relacionada:

Recolección de basura y documentación de Java 7 (JDK 7) en G1


4

CMS puede provocar una degradación lenta del rendimiento incluso si lo ejecuta sin acumular objetos permanentes. Esto se debe a la fragmentación de la memoria que supuestamente G1 evita.

El mito sobre G1 disponible solo con soporte pago es solo eso, un mito. Sun y ahora Oracle han aclarado esto en la página de JDK.


4

Se supone que G1 GC funciona mejor. Pero si configura -XX: MaxGCPauseMill es demasiado agresivo, la basura se recolectará demasiado lentamente. Y es por eso que GC completo se activó en el ejemplo de David Leppik.


4

Acabo de implementar G1 Garbage Collector en nuestro proyecto Terracotta Big Memory. Mientras trabajaba en diferentes tipos de colectores, G1 nos dio los mejores resultados con un tiempo de respuesta de menos de 600ms.

Puede encontrar los resultados de las pruebas (26 en total) aquí

Espero eso ayude.


3

Recientemente he migrado parte de Twicsy a un nuevo servidor con 128 GB de RAM y decidí utilizar 1.7. Comencé usando las mismas configuraciones de memoria que usé con 1.6 (tengo varias instancias ejecutándose haciendo varias cosas, desde 500 MB de pila hasta 15 GB, y ahora una nueva con 40 GB) y eso no funcionó bien en absoluto . 1.7 parece usar más montón que 1.6, y experimenté muchos problemas durante los primeros días. Afortunadamente, tenía mucha RAM para trabajar y aumenté la RAM para la mayoría de mis procesos, pero todavía tenía algunos problemas. Mi MO normal era usar un tamaño de montón mínimo muy pequeño de 16 m, incluso con un montón máximo de varios gigabytes, y luego activar GC incremental. Esto mantuvo las pausas al mínimo. Sin embargo, eso no funciona ahora, y tuve que aumentar el tamaño mínimo a aproximadamente lo que esperaba usar en promedio en el montón, y eso ha funcionado muy bien. Todavía tengo activado el GC incremental, pero lo intentaré sin. Ahora no hay pausas en absoluto, y las cosas parecen ir muy rápido. Entonces, creo que la moraleja de la historia es que no espere que la configuración de su memoria se traduzca perfectamente de 1.6 a 1.7.


2

G1 hace que la aplicación sea mucho más ágil: aumentará la latencia de la aplicación; la aplicación puede denominarse "soft-real-time". Esto se hace reemplazando dos tipos de ejecuciones de GC (pequeñas y menores y una grande en Tenured Gen) por pequeñas de igual tamaño.

Para obtener más detalles, consulte esto: http://geekroom.de/java/java-expertise-g1-fur-java-7/


1

Estoy trabajando con Java, para Heap pequeño y grande, y la cuestión de GC y Full GC aparece todos los días, ya que las restricciones pueden ser más estrictas que otras: en cierto entorno, 0.1 segundos de scavenger GC o Full GC, kill simplemente la funcionalidad, y tener una configuración fina y la capacidad es importante (CMS, iCMS, otros ... el objetivo está aquí para tener el mejor tiempo de respuesta posible con el tratamiento en tiempo casi real (aquí el tratamiento en tiempo real suele ser de 25 ms) , así que, básicamente, ¡cualquier mejora en la ergonomía y heurística de GC es bienvenida!


1

Utilizo G1GC en Java 8 y también con Groovy (también Java 8), y estoy haciendo varios tipos de cargas de trabajo y, en general, G1GC funciona así:

  • El uso de memoria es muy bajo, por ejemplo, 100 MB en lugar de 500 MB en comparación con la configuración predeterminada de Java

  • El tiempo de respuesta es constante y muy bajo.

  • El rendimiento entre la configuración predeterminada y G1GC es un 20% de desaceleración cuando se usa G1GC en el peor de los casos (sin ajuste, aplicación de un solo subproceso). No es mucho considerar un buen tiempo de respuesta y un bajo uso de memoria.

  • Cuando se ejecuta desde Tomcat, que es multiproceso, el rendimiento general es un 30% mejor y el uso de la memoria es mucho menor y los tiempos de respuesta son mucho menores.

Entonces, en general, cuando se utilizan cargas de trabajo realmente diversas, G1GC es un muy buen recopilador de Java 8 para aplicaciones de múltiples subprocesos, e incluso para las de un solo subproceso hay algunos beneficios.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.