2010-09-09 10 views
8

Tengo una aplicación de alto volumen de Java que maneja una carga constante de 50000msgs/seg. Se está sintonizado para un alto rendimiento usando los siguientes ajustes:¿Por qué los tiempos de GC aumentan constantemente en una aplicación Java de alto volumen y larga ejecución?

-Xmx3g -Xms3g -XX: NewSize = 2g -Xss128k -XX: SurvivorRatio = 6 -XX: TargetSurvivorRatio = 90 -XX: + UseParallelGC -XX: ParallelGCThreads = 12 -XX: + UseParallelOldGC -XX: + HeapDumpOnOutOfMemoryError

Estoy descubriendo que los tiempos de los jóvenes GC constantemente aumentan de 50 ms cuando comienza a 200 ms para el final del día, aunque la frecuencia de carreras de GC sigue siendo la misma.

Si pruebo la misma ejecución con el colector ParNewGC, los tiempos de GC aumentan mucho más rápido. ¿Alguien tiene alguna idea sobre este problema?

+0

¿Al día siguiente empeora con el tiempo, es decir, supera los 200 ms o reinicia la aplicación cada día? – JoseK

+0

Supongo, pero ¿no es esto solo un efecto secundario de NewSize que es realmente grande? GC-ing en 2 gigas de objetos parece que llevaría un tiempo. – wds

Respuesta

3

Si tiene una pérdida de memoria o una memoria caché en memoria que está usando gradualmente más y más memoria, esto tendría el efecto de hacer que el GC haga más trabajo rastreando los objetos alcanzables.

Otras posibilidades son:

  • que tiene una fuga de memoria no montón, y que se traduce en el aumento de paginación; es decir, copia de páginas de memoria física en el disco y viceversa.

  • Algunos procesos externos consumen cantidades cada vez mayores de memoria, lo que aumenta la búsqueda.

  • La naturaleza de los objetos generados en la generación joven está cambiando con el tiempo, por lo que se necesita más trabajo para rastrear los objetos alcanzables. Puede ser simplemente que una mayor proporción de ellos sobrevivan después de la primera colección.

+0

He comprobado que no hay pérdida de memoria, las gráficas de las generaciones jóvenes, titulares y antiguas son todas periódicas. –

2

Puede ser una combinación de varios factores:

  • una pérdida de memoria real. (Todavía se hace referencia a los objetos por accidente)
  • Más objetos, o tal vez una distribución diferente de los objetos entre los pools de gc.
  • El montón es más grande. Trace el tiempo-gc y el tamaño del montón.
  • Fragmentación de la memoria. En el nivel del sistema operativo y/o el montón de Java, dependiendo de la jvm.

¿Por qué no trazas el número de objetos, el tamaño del montón y el tiempo de gc? (usando una herramienta, o cuestionando MBeans) Una gráfica debería indicar la tendencia; aumentar, disminuir o lineal, y lo ayudará a determinar si hay una fuga. Si es posible, también descargue algunas estadísticas de su programa, como el número de mensajes procesados ​​o sesiones activas, etc.

¿Es un problema real ya que sus mensajes no se procesan durante gc ?. Pruebe la marca concurrente y barrer gc ...

* -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 
+0

Estoy bastante seguro de que esto no es una pérdida de memoria porque puedo ver que el gen joven oscila de 100MB a 2GB, periódicamente. Casi toda la carga de nuevos obejcts se borran en la generación joven misma. Si establezco un tamaño de pila de gen jóven más pequeño, entonces no podría manejar una inundación repentina de mensajes. –

+0

He intentado -XX: + UseConcMarkSweepGC -XX: + UseParNewGC y el problema empeoró. Consideré la fragmentación de la memoria, pero no estoy seguro de cómo averiguar si esta es la causa. –

+0

Tuve que leer la guía de sintonización de gc, e indica que tanto el gc paralelo como la marca y el barrido simultáneos son más propensos a causar fragmentación. Entonces, como empeoró al usar concMarkSweep, podría indicar que es realmente la fragmentación que está viendo. Pruebe estos dos consejos de la guía y vea si mejoran ... "Reducir el número de subprocesos de recolector de basura reducirá este efecto de fragmentación y aumentará el tamaño de la generación de tiempo fijo". – KarlP

Cuestiones relacionadas