Pregunta

Forma corta: El colector de basura CMS parece ser no poder cobrar una cantidad cada vez mayor de la basura; finalmente, nuestra JVM se llena, y la aplicación deja de responder. Forzar un GC a través de una herramienta externa (JConsole o jmap -histo:live) lo limpia una vez.

ACTUALIZACIÓN: El problema parece estar relacionado con el plugin para JTop JConsole; si no corremos JConsole, o bien puede hacerlo sin el plugin JTop, el comportamiento desaparece.

(Notas técnicas:.. Nos estamos quedando Sun JDK 1.6.0_07, de 32 bits, en una máquina Linux 2.6.9 Actualización de la versión del JDK no es realmente una opción, a menos que haya una razón inevitable, importante también, nuestra sistema no está conectado a una máquina accesible por Internet, por lo que las capturas de JConsole, etc, no son una opción.)

Actualmente estamos ejecutando nuestra JVM con las siguientes banderas:

-server -Xms3072m -Xmx3072m -XX:NewSize=512m -XX:MaxNewSize=512m 
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled 
-XX:CMSInitiatingOccupancyFraction=70 
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 
-XX:+DisableExplicitGC

Al observar el gráfico de la memoria en JConsole, hay un total de GC que se ejecute cada ~ 15 minutos más o menos durante las primeras horas de vida útil de nuestra aplicación; después de cada GC completa, hay más y más memoria todavía está en uso. Después de unas horas, el sistema realiza un estado de equilibrio donde hay aproximadamente 2 GB de memoria utilizada en la antigua generación de CMS.

que suena como una pérdida de memoria clásico, excepto que si utilizamos cualquier herramienta que las fuerzas de un GC completa (pulsando el botón de "limpieza de la memoria" en JConsole, o correr jmap -histo:live, etc), la vieja generación cae repentinamente a ~ 500 MB utilizados y nuestra aplicación se vuelve a responder de nuevo para las próximas horas (tiempo durante el cual el mismo patrón continúa -. después de cada GC completa, más y más de la vieja generación está llena)

Una cosa de la nota: en JConsole, informó el recuento ConcurrentMarkSweep GC permanecerá a 0 hasta que forzar un GC con jconsole / jmap / etc

.

El uso de jmap -histo y jmap -histo:live en secuencia, soy capaz de determinar que los objetos aparentemente sin cobrar consisten en:

  • varios millones de HashMaps y matrices de HashMap$Entry (en una relación 1: 1)
  • varios millones Vectors y matrices objeto (relación 1: 1, y aproximadamente el mismo que el número de HashMaps)
  • varios millones de HashSet, Hashtable, y com.sun.jmx.remote.util.OrderClassLoaders, así como matrices de Hashtable$Entry (aproximadamente el mismo número de cada uno; aproximadamente la mitad que los HashMaps y vectores)

Hay algunos extractos de la salida de GC a continuación; mi interpretación de ellos parece ser que el CMS GC se está abortado sin faltar a la parada GC-el-mundo. Estoy malinterpretando esta salida de alguna manera? ¿Hay algo que haría que?

Durante el tiempo de ejecución normal, los bloques de salida CMS GC se ven más o menos así:

36301.827: [GC [1 CMS-initial-mark: 1856321K(2621330K)] 1879456K(3093312K), 1.7634200 secs] [Times: user=0.17 sys=0.00, real=0.18 secs]
36303.638: [CMS-concurrent-mark-start]
36314.903: [CMS-concurrent-mark: 7.804/11.264 secs] [Times: user=2.13 sys=0.06, real=1.13 secs]
36314.903: [CMS-concurrent-preclean-start]
36314.963: [CMS-concurrent-preclean: 0.037/0.060 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
36314.963: [CMS-concurrent-abortable-preclean-start]
36315.195: [GC 36315.195: [ParNew: 428092K->40832K(471872K), 1.1705760 secs] 2284414K->1897153K(3093312K), 1.1710560 secs] [Times: user=0.13 sys=0.02, real=0.12 secs]
CMS: abort preclean due to time 36320.059: [CMS-concurrent-abortable-preclean: 0.844/5.095 secs] [Times: user=0.74 sys=0.05, real=0.51 secs]
36320.062: [GC[YG occupancy: 146166 K (471872 K)]36320.062: [Rescan (parallel), 1.54078550 secs]36321.603: [weak refs processing, 0.0042640 secs] [1 CMS-remark: 1856321K(2621440K)] 2002488K(3093312K), 1.5456150 secs] [Times: user=0.18 sys=0.03, real=0.15 secs]
36321.608: [CMS-concurrent-sweep-start]
36324.650: [CMS-concurrent-sweep: 2.686/3.042 secs] [Times: uesr=0.66 sys=0.02, real=0.30 secs]
36324.651: [CMS-concurrent-reset-start]
36324.700: [CMS-concurrent-reset: 0.050/0.050 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]

Y eso es todo; la línea siguiente será el próximo ParNew GC.

Cuando forzamos un GC usando -histo jmap: en vivo, que en vez obtenemos:

48004.088: [CMS-concurrent-mark: 8.012/8.647 secs] [Times: user=1.15 sys=0.02, real=0.87 secs]
(concurrent mode interrupted)

seguido de ~ 125 líneas de la forma a continuación: (algunos GeneratedMethodAccessor, algunos GeneratedSerializationConstructorAccessor, algunos GeneratedConstructorAccessor, etc)

[Unloading class sun.reflect.GeneratedMethodAccessor3]

seguido de:

: 1911295K->562232K(2621440K), 15.6886180 secs] 2366440K->562232K(3093312K), [CMS Perm: 52729K->51864K(65536K)], 15.6892270 secs] [Times: user=1.55 sys=0.01, real=1.57 secs]

Gracias de antemano!

¿Fue útil?

Solución

com.sun.jmx.remote.util.OrderClassLoader se utiliza en la capa remote'ing de JMX y una revisión rápida del código sugiere que están creados como parte del proceso de unmarshalling para solicitudes remotas dentro de la JVM. La vida útil de los cargadores de clases estará directamente relacionado con el tiempo de vida de la cosa que era unmarshalled de tal manera que una vez que ya no hay ninguna referencia a lo que el cargador de clases podría ser liberado.

Me no se sorprenda si en este caso la presencia de estos casos fue el resultado directo de que el uso de JConsole para examinar los acontecimientos en la JVM. Y parece que acababan de ser limpiados por CG como parte de su funcionamiento normal.

supongo que es posible hay un error en la implementación de JMX (parece poco probable en un tiempo relativamente hasta a la fecha de JVM) o tal vez usted tiene algunas MBeans personalizados o están utilizando algunas herramientas JMX personalizados que están causando el problema. Pero en última instancia, estoy sospechando la OrderClassLoader es probablemente una pista falsa y el problema está en otra parte (GC roto o algún otro fugas).

Otros consejos

  

Notas técnicas: nos estamos quedando Sun JDK   1.6.0_07, de 32 bits, en una máquina Linux 2.6.9. Actualización de la versión del JDK no es   realmente una opción, a menos que haya una   inevitable, las principales razones.

Varias versiones más recientes de Java han tenido actualizaciones al recolector de basura CMS. Cabe destacar que 6u12, 6u14, y 6u18.

No soy un experto con GC cosas, pero estoy adivinando las correcciones PRECLEAN en 6u14 pueden solucionar el problema que se está viendo. Por supuesto, podría decir lo mismo acerca de los errores de descarga 6u18 clase. Como he dicho, no soy un experto en la materia GC.

Existen soluciones para:

  • 6u10: (afecta 6u4 +) CMS nunca se borra referentes al -XX: + ParallelRefProcEnabled
  • 6u12: CMS: codificación incorrecta de matrices de objetos sobrevolado durante concurrente limpieza previa
  • 6u12: CMS: manipulación de desbordamiento incorrecta cuando se utiliza concurrente paralelo marcado
  • 6u14: CMS: error de aserción "is_cms_thread == Tema :: current () -> is_ConcurrentGC_thread ()"
  • 6u14: CMS: CMSInitiatingPermOccupancyFraction Necesidad para la ondulación permanente, divorciándose de CMSInitiatingOccupancyFraction
  • 6u14: CMS afirman: _concurrent_iteration_safe_limit actualización perdió
  • 6u14: CMS: la manipulación incorrecta de desbordamiento durante la limpieza previa de las listas de referencias
  • 6u14: SIGSEGV o (! Is_null (v), "valor oop nunca puede ser cero") cuando se ejecuta con la afirmación de la CMS y cooperativas
  • 6u14: CMS:. Livelock en CompactibleFreeListSpace :: block_size ()
  • 6u14: Hacer el trabajo con CMS comprimido Uy
  • 6u18: CMS: volcado de memoria con -XX: + UseCompressedOops
  • 6u18: CMS: errores relacionados con la descarga de clase
  • 6u18: CMS: ReduceInitialCardMarks inseguro en presencia de CMS limpieza previa
  • 6u18: [Regresión] -XX: NewRatio con -XX: + UseConcMarkSweepGC provoca error fatal
  • 6u20: marcas de tarjetas se pueden diferir demasiado tiempo

Además de todo lo anterior, 6u14 también introdujo el G1 recolector de basura, aunque todavía está en pruebas. G1 está destinada a sustituir la CMS en Java 7.

G1 se puede utilizar en Java 6u14 y más reciente con la siguiente línea de comandos:

-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC

Me gustaría empezar con algo mucho más simple, como:

-server -Xms3072m -Xmx3072m -XX:+UseParallelOldGC -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 

Y a ver si este se adapte a sus necesidades.

Parece que usted está construyendo objetos que volver a sus propietarios (los puntos A a los puntos B a A) punto. Este resultado en la cuenta de referencia mayor que cero restantes, por lo que el recolector de basura no puede limpiarlos. Es necesario romper el ciclo cuando se suelte. Anulando la referencia en A o B va a resolver el problema. Esto funciona incluso en grandes miradas de referencia iguales (A -> B -> C -> D -> A). Los vectores y matrices de objetos pueden ser utilizados por sus HashMaps.

El presense de los cargadores a distancia puede indicar una falta de limpieza y referencias cerca de objetos cargados a través de JNDI u otro método de acceso remoto.

EDIT: Me tomó un segundo vistazo a su última línea. Es posible que desee aumentar la asignación permanente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top