create - layout java jframe
Sintonización GC-previniendo un GC completo (5)
Estoy atendiendo solicitudes y espero que, más allá de una cierta cantidad de objetos compartidos, todos los demás objetos sean útiles solo para la solicitud en cuestión. Esa es la teoría, pero cualquier tipo de caché puede anular fácilmente esa suposición y crear objetos que viven más allá de la solicitud.
Como otros no han notado, ni su gran generación joven ni la tenencia extendida parecen funcionar.
Debes perfilar tu aplicación y analizar la distribución por edad de los objetos. Estoy bastante seguro de que Grails almacena en caché todo tipo de cosas más allá del alcance de una solicitud y eso es lo que se filtra en la vieja generación.
Lo que esencialmente intentas es sacrificar los tiempos de pausa de la generación joven (para una generación joven de 2 GB) para posponer lo inevitable: una colección de generación antigua de 6 GB. Esto no es exactamente una buena compensación que estás haciendo allí.
En su lugar, probablemente debería apuntar a mejores tiempos de pausa de los géneros jóvenes y permitir que CMS queme más tiempo de CPU: más subprocesos de GC de fase actual (no puedo recordar la opción para esa opción), mayor GCTimeRatio
, un MaxGCPauseMillis
> MaxGCMinorPauseMillis
para tomar la presión de colecciones menores y les permite cumplir sus objetivos de pausa en lugar de tener que cambiar su tamaño para ajustarse al límite de la colección principal.
Para hacer que los principales GCs sean menos dolorosos, puede leer esto: http://blog.ragozin.info/2012/03/secret-hotspot-option-improving-gc.html (este parche debe estar en j7u4). CMSParallelRemarkEnabled
debería estar habilitado, no estoy seguro de si este es el valor predeterminado.
Alternativa: utilizar G1GC
Personalmente, tengo algunas experiencias horribles con G1GC trabajando en una esquina debido a algunas cargas de trabajo muy grandes de tipo LRU y luego retrocediendo a una gran colección Stop-the-world mucho más a menudo que CMS experimentó fallas en el modo concurrente para la misma carga de trabajo.
Pero para otras cargas de trabajo (como la suya), en realidad podría hacer el trabajo y recopilar la generación anterior de manera incremental, al mismo tiempo que se compacta y evita así grandes pausas.
Pruébalo si aún no lo has hecho. Nuevamente, actualice al java7 más reciente antes de hacerlo, G1 todavía tiene algunos problemas con sus heurísticas que están tratando de resolver.
Edición: Oracle ha mejorado las heurísticas de G1GC y algunos cuellos de botella desde que escribí esta respuesta. Definitivamente debería valer la pena intentarlo ahora.
Otra alternativa: colector de rendimiento.
Como ya está utilizando un colector paralelo para una generación joven de 2GB y salga con los tiempos de pausa de 200 ms ... ¿por qué no prueba el colector de la antigua generación paralela en su montón de 6G? Probablemente tomaría menos de 10s + grandes colecciones que estás viendo con CMS. Cada vez que el CMS se ejecuta en uno de sus modos de falla, realiza una recopilación de un solo hilo para detener el mundo.
Estoy intentando evitar que el GC completo (del ejemplo de gc.log a continuación) ejecute una aplicación Grails en Tomcat en producción. ¿Alguna sugerencia sobre cómo configurar mejor el GC?
14359.317: [Full GC 14359.317: [CMS: 3453285K-> 3099828K (4194304K), 13.1778420 secs] 4506618K-> 3099828K (6081792K) para obtener el máximo de precios. : usuario = 13.15 sys = 0.04, real = 13.18 segundos]
Mis parámetros de VM son los siguientes:
-Xms = 6G
-Xmx = 6G
-XX: MaxPermSize = 1G
-XX: NewSize = 2G
-XX: MaxTenuringThreshold = 8
-XX: SurvivorRatio = 7
-XX: + UseConcMarkSweepGC
-XX: + CMSClassUnloadingEnabled
-XX: + CMSPermGenSweepingEnabled
-XX: + CMSIncrementalMode
-XX: CMSInitiatingOccupancyFraction = 60
-XX: + UseCMSInitiatingOccupancyOnly
-XX: + HeapDumpOnOutOfMemoryError
-XX: + PrintGCDetails
-XX: + PrintGCTimeStamps
-XX: + PrintTenuringDistribution
-Dsun.reflect.inflationThreshold = 0
14169.764: [GC 14169.764: [ParNew Desired survivor size 107347968 bytes, new threshold 8 (max 8) - age 1: 15584312 bytes, 15584312 total - age 2: 20053704 bytes, 35638016 total - age 3: 13624872 bytes, 49262888 total - age 4: 14469608 bytes, 63732496 total - age 5: 10553288 bytes, 74285784 total - age 6: 11797648 bytes, 86083432 total - age 7: 12591328 bytes, 98674760 total : 1826161K->130133K(1887488K), 0.1726640 secs] 5216326K->3537160K(6081792K) icms_dc=0 , 0.1733010 secs] [Times: user=0.66 sys=0.03, real=0.17 secs] 14218.712: [GC 14218.712: [ParNew Desired survivor size 107347968 bytes, new threshold 8 (max 8) - age 1: 25898512 bytes, 25898512 total - age 2: 10308160 bytes, 36206672 total - age 3: 16927792 bytes, 53134464 total - age 4: 13493608 bytes, 66628072 total - age 5: 14301832 bytes, 80929904 total - age 6: 10448408 bytes, 91378312 total - age 7: 11724056 bytes, 103102368 total - age 8: 12299528 bytes, 115401896 total : 1807957K->147911K(1887488K), 0.1664510 secs] 5214984K->3554938K(6081792K) icms_dc=0 , 0.1671290 secs] [Times: user=0.61 sys=0.00, real=0.17 secs] 14251.429: [GC 14251.430: [ParNew Desired survivor size 107347968 bytes, new threshold 7 (max 8) - age 1: 25749296 bytes, 25749296 total - age 2: 20111888 bytes, 45861184 total - age 3: 7580776 bytes, 53441960 total - age 4: 16819072 bytes, 70261032 total - age 5: 13209968 bytes, 83471000 total - age 6: 14088856 bytes, 97559856 total - age 7: 10371160 bytes, 107931016 total - age 8: 11426712 bytes, 119357728 total : 1825735K->155304K(1887488K), 0.1888880 secs] 5232762K->3574222K(6081792K) icms_dc=0 , 0.1895340 secs] [Times: user=0.74 sys=0.06, real=0.19 secs] 14291.342: [GC 14291.343: [ParNew Desired survivor size 107347968 bytes, new threshold 7 (max 8) - age 1: 25786480 bytes, 25786480 total - age 2: 21991848 bytes, 47778328 total - age 3: 16650000 bytes, 64428328 total - age 4: 7387368 bytes, 71815696 total - age 5: 16777584 bytes, 88593280 total - age 6: 13098856 bytes, 101692136 total - age 7: 14029704 bytes, 115721840 total : 1833128K->151603K(1887488K), 0.1941170 secs] 5252046K->3591384K(6081792K) icms_dc=0 , 0.1947390 secs] [Times: user=0.82 sys=0.04, real=0.20 secs] 14334.142: [GC 14334.143: [ParNew Desired survivor size 107347968 bytes, new threshold 6 (max 8) - age 1: 31541800 bytes, 31541800 total - age 2: 20826888 bytes, 52368688 total - age 3: 19155264 bytes, 71523952 total - age 4: 16422240 bytes, 87946192 total - age 5: 7235616 bytes, 95181808 total - age 6: 16549000 bytes, 111730808 total - age 7: 13026064 bytes, 124756872 total : 1829427K->167467K(1887488K), 0.1890190 secs] 5269208K->3620753K(6081792K) icms_dc=0 , 0.1896630 secs] [Times: user=0.80 sys=0.03, real=0.19 secs] 14359.317: [Full GC 14359.317: [CMS: 3453285K->3099828K(4194304K), 13.1778420 secs] 4506618K->3099828K(6081792K), [CMS Perm : 261951K->181304K(264372K)] icms_dc=0 , 13.1786310 secs] [Times: user=13.15 sys=0.04, real=13.18 secs] 14373.287: [GC [1 CMS-initial-mark: 3099828K(4194304K)] 3100094K(6081792K), 0.0107380 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 14373.298: [CMS-concurrent-mark-start] 14472.579: [GC 14472.579: [ParNew Desired survivor size 107347968 bytes, new threshold 8 (max 8) - age 1: 42849392 bytes, 42849392 total : 1677824K->86719K(1887488K), 0.1056680 secs] 4777652K->3186547K(6081792K) icms_dc=0 , 0.1063280 secs] [Times: user=0.61 sys=0.00, real=0.11 secs] 14506.980: [GC 14506.980: [ParNew Desired survivor size 107347968 bytes, new threshold 8 (max 8) - age 1: 42002904 bytes, 42002904 total - age 2: 35733928 bytes, 77736832 total : 1764543K->96136K(1887488K), 0.0982790 secs] 4864371K->3195964K(6081792K) icms_dc=0 , 0.0988960 secs] [Times: user=0.53 sys=0.01, real=0.10 secs] 14544.285: [GC 14544.286: [ParNew Desired survivor size 107347968 bytes, new threshold 8 (max 8) - age 1: 26159736 bytes, 26159736 total - age 2: 37842840 bytes, 64002576 total - age 3: 33192784 bytes, 97195360 total : 1773960K->130799K(1887488K), 0.1208590 secs] 4873788K->3230628K(6081792K) icms_dc=0 , 0.1215900 secs] [Times: user=0.59 sys=0.02, real=0.13 secs] 14589.266: [GC 14589.266: [ParNew Desired survivor size 107347968 bytes, new threshold 4 (max 8) - age 1: 28010360 bytes, 28010360 total - age 2: 21136704 bytes, 49147064 total - age 3: 35081376 bytes, 84228440 total - age 4: 32468056 bytes, 116696496 total : 1808623K->148284K(1887488K), 0.1423150 secs] 4908452K->3248112K(6081792K) icms_dc=0 , 0.1429440 secs] [Times: user=0.70 sys=0.02, real=0.14 secs] 14630.947: [GC 14630.947: [ParNew Desired survivor size 107347968 bytes, new threshold 8 (max 8) - age 1: 28248240 bytes, 28248240 total - age 2: 20712320 bytes, 48960560 total - age 3: 18217168 bytes, 67177728 total - age 4: 34834832 bytes, 102012560 total : 1826108K->140347K(1887488K), 0.1784680 secs] 4925936K->3275469K(6081792K) icms_dc=0 , 0.1790920 secs] [Times: user=0.98 sys=0.03, real=0.18 secs] 14664.779: [GC 14664.779: [ParNew Desired survivor size 107347968 bytes, new threshold 5 (max 8) - age 1: 25841000 bytes, 25841000 total - age 2: 22264960 bytes, 48105960 total - age 3: 17730104 bytes, 65836064 total - age 4: 17988048 bytes, 83824112 total - age 5: 34739384 bytes, 118563496 total : 1818171K->147603K(1887488K), 0.1714160 secs] 4953293K->3282725K(6081792K) icms_dc=0 , 0.1720530 secs] [Times: user=0.82 sys=0.11, real=0.17 secs] 14702.488: [GC 14702.489: [ParNew Desired survivor size 107347968 bytes, new threshold 8 (max 8) - age 1: 26887368 bytes, 26887368 total - age 2: 21403352 bytes, 48290720 total - age 3: 18732224 bytes, 67022944 total - age 4: 17640576 bytes, 84663520 total - age 5: 17942952 bytes, 102606472 total : 1825427K->142695K(1887488K), 0.2118320 secs] 4960549K->3312168K(6081792K) icms_dc=0 , 0.2124630 secs] [Times: user=1.13 sys=0.14, real=0.21 secs]
La estrategia a la que apuntaba: quiero limitar al mínimo lo que obtiene el titular, estoy atendiendo solicitudes y espero que más allá de una cierta cantidad de objetos compartidos, todos los demás objetos sean útiles solo para la solicitud en cuestión. Por lo tanto, mediante el uso de un gran tamaño NewSize y un aumento de TenuringThreshold y esperaba que ninguno de estos objetos de servicio único se quedara.
Los siguientes están ahí para apoyar mi estrategia:
-Xms = 6G
-Xmx = 6G
-XX: NewSize = 2G // espacio grande para que ParNew no ocurra con frecuencia y deje que los objetos caduquen
-XX: MaxTenuringThreshold = 8 // para limitar un poco más la tenencia
-XX: SurvivorRatio = 7 // basado en ejemplos -XX: CMSInitiatingOccupancyFraction = 60
// para evitar que un GC total provocado por la asignación de la promoción haya fallado
-XX: + UseCMSInitiatingOccupancyOnly
// ir con el anterior basado en el ejemplo
MaxPermSize = 1G y "-Dsun.reflect.inflationThreshold = 0" están relacionados con otro problema que preferiría mantener separado.
"-XX: + CMSClassUnloadingEnabled" y "-XX: + CMSPermGenSweepingEnabled" están ahí debido a los grails que dependen en gran medida y las clases adicionales para cierres y reflexiones
-XX: + CMSIncrementalMode es un experimento que no ha tenido mucho éxito
A continuación se muestra mi configuración para el cuadro de Linux de 4 núcleos.
En mi experiencia, puede ajustar -XX: NewSize -XX: MaxNewSize -XX: GCTimeRatio para lograr un alto rendimiento y una baja latencia.
-servidor
-Xms2048m
-Xmx2048m
-Dsun.rmi.dgc.client.gcInterval = 86400000
-Dsun.rmi.dgc.server.gcInterval = 86400000
-XX: + Puntos agresivos
-XX: GCTimeRatio = 20
-XX: + UseParNewGC
-XX: ParallelGCThreads = 4
-XX: + CMSParallelRemarkEnabled
-XX: ParallelCMSThreads = 2
-XX: + CMSScavengeBeforeRemark
-XX: + UseConcMarkSweepGC
-XX: + UseCMSInitiatingOccupancyOnly
-XX: CMSInitiatingOccupancyFraction = 50
-XX: NewSize = 512m
-XX: MaxNewSize = 512m
-XX: PermSize = 256m
-XX: MaxPermSize = 256m
-XX: SurvivorRatio = 90
-XX: TargetSurvivorRatio = 90
-XX: MaxTenuringThreshold = 15
-XX: MaxGCMinorPauseMillis = 1
-XX: MaxGCPauseMillis = 5
-XX: + PrintGCDateStamps
-XX: + PrintGCDetails
-XX: + PrintTenuringDistribution
-Xloggc: ./ logs / gc.log
El fragmento de registro publicado muestra que usted tiene una cantidad sustancial de objetos que están vivos durante más de 320 s (aproximadamente 40 s por colección joven y los objetos sobreviven a través de 8 colecciones antes de la promoción). Los objetos restantes se vuelven sangrados y eventualmente alcanzas un CG total aparentemente inesperado que en realidad no se acumula mucho.
3453285K->3099828K(4194304K)
es decir, tienes un tenedor 4G que está lleno al 82% (3453285/4194304) cuando se activa y está lleno al 74% después de 13 segundos.
Esto significa que se necesitaron 13 segundos para reunir el total de ~ 350M, lo que, en el contexto de un montón de 6G no es mucho.
Básicamente, esto significa que su montón no es lo suficientemente grande o, quizás más probable, tiene una pérdida de memoria. Una fuga como esta es una cosa terrible para CMS porque una recopilación de tenencia concurrente es un evento no compacto, lo que significa que la tenencia es una colección de listas libres, lo que significa que la fragmentación puede ser un gran problema para el CMS, lo que significa que su utilización de tenencia se vuelve cada vez más ineficiente. significa que hay una mayor probabilidad de eventos de fallos de promoción (aunque si esto fuera un evento así, esperaría ver un mensaje de registro que diga eso) porque quiere promocionar (o cree que tendrá que promocionar) X MB en titular. pero no tiene una lista libre (contigua)> = X MB disponible. Esto desencadena una recopilación permanente inesperada que no es un evento STW concurrente de forma remota. Si realmente tienes muy poco para coleccionar (como lo haces), no es de extrañar que estés sentado moviendo tus pulgares.
Algunos consejos generales, en gran parte reiterando lo que Vladimir Sitnitov ha dicho ...
- el uso de iCMS en una caja multinúcleo no tiene sentido (a menos que tenga muchas JVM u otros procesos ejecutándose en esa caja, de manera que la JVM no tenga suficiente CPU), por lo tanto, elimine este interruptor
- sus colecciones jóvenes son innecesariamente largas debido al impacto de copiar cantidades relativamente importantes de memoria entre los espacios de sobrevivientes en cada colección, 150-200ms es una colección ParNew realmente bastante masiva
- La respuesta correcta a la cuestión de la generación joven depende de cuál sea realmente el comportamiento de la asignación (por ejemplo, tal vez sea mejor que tenga un tiempo de tenencia anticipada y reduzca el impacto de la fragmentación en las colecciones con tenencia O tal vez sea mejor tener una noticia mucho más masiva). gen y la reducción de la frecuencia de las colecciones de genes jóvenes, de manera que se promocionen menos objetos, de modo que se produzca un sangrado mínimo en el tenencia).
Algunas preguntas...
- ¿Va eventualmente OOM o se recupera?
- ¿está la aplicación en un estado estable (sujeta a una carga constante en algún punto más allá del inicio) durante este fragmento de registro o está bajo presión?
El tamaño de su sobreviviente no está disminuyendo mucho, si es que lo hace, idealmente debería estar disminuyendo abruptamente, porque solo desea que una minoría de objetos sobreviva lo suficiente para llegar a la vieja generación.
Esto sugiere que muchos objetos están viviendo un tiempo relativamente largo, lo que puede suceder cuando tienes muchas conexiones abiertas, hilos, etc. que no se manejan rápidamente, por ejemplo.
(¿Tiene alguna opción para cambiar la aplicación, incidentalmente, o solo puede modificar la configuración del GC? También podría haber una configuración de Tomcat que podría tener un efecto ...)
Por favor, describa cuántas CPU se pueden usar para Tomcat? 4?
¿Qué versión de java estás usando? (> 1.6.0u23?)
0) Desde la salida de Full GC, definitivamente parece que está alcanzando el límite de memoria: incluso después de gc completo, todavía hay 3099828K de memoria usada (de 4194304K). Simplemente no hay forma de prevenir el Full GC cuando se queda sin memoria.
¿Se espera un conjunto de trabajo de 3.1Gb para su aplicación? Eso es 3.1Gb de memoria no basura!
Si se espera eso, es hora de aumentar -Xmx / -Xms. De lo contrario, es el momento de recopilar y analizar el volcado del montón para identificar la memoria de memoria.
Después de resolver el problema del conjunto de trabajo de 3Gb, puede encontrar útiles los siguientes consejos: Desde mi punto de vista, vale la pena probar el modo de CMS normal (no incremental) y reducir NewSize.
1) El modo incremental está dirigido a máquinas cpu individuales, cuando el subproceso del CMS entrega la CPU a otros subprocesos.
En caso de que tenga alguna CPU de repuesto (por ejemplo, si está ejecutando una máquina multinúcleo), es mejor realizar GC en segundo plano sin rendimientos.
Por lo tanto, recomendaría eliminar -XX: + CMSIncrementalMode.
2) -XX: CMSInitiatingOccupancyFraction = 60 le dice a CMS que inicie GC en segundo plano después de que OLD gen esté completo al 60%.
En caso de que haya basura en el montón, y CMS no se mantenga al día, tiene sentido reducir CMSInitiatingOccupancyFraction. Por ejemplo, -XX: CMSInitiatingOccupancyFraction = 30, así que CMS iniciará la recopilación concurrente cuando la generación anterior esté llena al 30%. Actualmente es difícil saber si es así, ya que simplemente no tiene basura en el montón.
3) Parece que la "tenencia prolongada" no ayuda: los objetos simplemente no se extinguen, incluso después de las tenencias de 7-8. Recomendaría reducir SurvivorRatio (por ejemplo, SurvivorRatio = 2, o simplemente eliminar la opción y seguir con el valor predeterminado). Eso reduciría el número de tenencias resultantes en una reducción de las pausas de menor importancia de las CG.
4) -XX: NewSize = 2G. ¿Intentaste valores más bajos para NewSize? Diga, NewSize = 512m. Eso debería reducir las pausas menores de Gc y hacer que las promociones sean más jóvenes,> menos masivas, simplificando el trabajo para CMS.