2010-05-19 15 views
9

Ocasionalmente, en algún lugar entre una vez cada 2 días a una vez cada 2 semanas, mi aplicación se bloquea en un lugar aparentemente aleatorio en el código con: java.lang.OutOfMemoryError: GC overhead limit exceeded. Si I Google este error llego a this SO question y que me llevan a this piece of sun documentation cuales expains:Duración del tiempo GC excesivo en "java.lang.OutOfMemoryError: el límite superior del GC excedió"

The parallel collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.

Lo que me que mi solicitud está aparentemente gastando el 98% del tiempo total en la recolección de basura dice para recuperar sólo el 2% de la montón.

¿Pero 98% de qué tiempo? ¿El 98% de las dos semanas completas que la aplicación ha estado funcionando? 98% del último milisegundo?

Estoy tratando de determinar el mejor enfoque para resolver realmente este problema en lugar de solo usar -XX:-UseGCOverheadLimit, pero siento la necesidad de comprender mejor el problema que estoy resolviendo.

+3

De los documentos, parece ser el 98% de las 2 semanas completas. Ha habilitado los registros de GC con estos indicadores -verbose: gc -XX: + PrintGCDetails XX: + PrintGCTimeStamps -Xloggc: PATH_FROM_ROOT/gclog.log. Sería bueno ver el tiempo de ejecución de la aplicación y el tiempo de parada debido a GC. – JoseK

+0

El registro de GC es una buena sugerencia. Lo intentaré. El 98% de las 2 semanas parece improbable pero tiene razón, eso es lo que implican los documentos. Espero que sea solo una escritura imprecisa –

+0

¿Has descubierto el significado del 98% del tiempo? Mi opinión es que GC debe estar ocupado ocupando el 98% de la utilización de la aplicación en el mismo momento en que ocurre la excepción y no durante las 2 semanas. –

Respuesta

6

I'm trying to determine a best approach to actually solving this issue rather than just using -XX:-UseGCOverheadLimit but I feel a need to better understand the issue I'm solving.

Bueno, está usando demasiada memoria, y por lo que parece, es probable que se deba a una pérdida lenta de memoria.

Puede intentar aumentar el tamaño del montón con -Xmx, lo que ayudaría si esto no es una pérdida de memoria sino una señal de que su aplicación realmente necesita mucho almacenamiento y la configuración que tiene actualmente es de muy baja a muy baja. Si se trata de una pérdida de memoria, esto solo pospondrá lo inevitable.

Para investigar si se trata de una pérdida de memoria, solicite a la máquina virtual que descargue Heap en OOM utilizando el conmutador -XX:+HeapDumpOnOutOfMemoryError, y luego analice el volcado de pila para ver si hay más objetos de los que deberían. http://blogs.oracle.com/alanb/entry/heap_dumps_are_back_with es un muy buen lugar para comenzar.


Editar: El destino quiso que me pasó a encontrarse con este problema por mí mismo tan sólo un día después de que se hizo esta pregunta, en una aplicación de estilo por lotes. Esto no fue causado por una pérdida de memoria, y tampoco ayudó el aumento del tamaño del almacenamiento dinámico. Lo que hice fue en realidad Disminuir tamaño de pila (de 1GB a 256MB) para hacer GC completos más rápido (aunque algo más frecuente). YMMV, pero vale la pena intentarlo.

Edición 2: No todos los problemas resueltos por el montón más pequeño ... siguiente paso estaba permitiendo el G1 garbage collector que parece que hacer un mejor trabajo que la CMS.

+0

Estoy probando algunos perfiles, y voy a probar ese también. Gracias. –

+0

Fui en una ruta similar a la tuya, experimentando con parámetros. Finalmente, al aumentar el tamaño del almacenamiento dinámico y algunos ajustes de mi código (no he encontrado pérdidas de memoria) parece que resolvió mi problema. –

+0

¿por qué usaría CMS o G1 en una aplicación de estilo por lotes? ¿No es mejor el colector de rendimiento? – endless

1

El> 98% se medirá durante el mismo período en el que se recupera menos del 2% de la memoria.

Es muy posible que no haya un período fijo para esto. Por ejemplo, si el cheque de OOM se realizaría después de cada 1,000,000 de verificaciones en vivo de objetos. El tiempo que toma sería dependiente de la máquina.

Lo más probable es que no pueda "resolver" su problema agregando -XX:-UseGCOverheadLimit. El resultado más probable es que la aplicación se ralentice, use un poco más de memoria y luego llegue al punto donde el GC simplemente no recupera ninguna memoria. En cambio, arregle las pérdidas de memoria y luego (si todavía es necesario) aumente el tamaño de su pila.

1

But 98% of what time? 98% of the entire two weeks the application has been running? 98% of the last millisecond?

La respuesta simple es que no está especificado. Sin embargo, en la práctica, la heurística "funciona", por lo que no puede ser ninguna de las dos interpretaciones extremas que usted postuló.

Si realmente quería saber cuál es el intervalo en el que se realizan las mediciones, siempre podría leer el código fuente OpenJDK 6 o 7. Pero no me molestaría porque no te ayudaría a resolver tu problema.

El "mejor" enfoque es leer un poco sobre la sintonización (comenzando con las páginas de Oracle/Sun), y luego cuidadosamente "girar las perillas de sintonización". No es muy científico, pero el espacio del problema (con precisión prediciendo aplicación + rendimiento del GC) es "demasiado difícil", dadas las herramientas que están actualmente disponibles.

Cuestiones relacionadas