2010-08-11 13 views
9

Una aplicación que recientemente hemos comenzado a bloquear de forma esporádica con un mensaje sobre "java.lang.OutOfMemoryError: 8589934608 bytes solicitados para Chunk :: new. ¿Espacio fuera de intercambio?".Java JIT Compiler causando OutOfMemoryError

He mirado alrededor en la red, y en todas partes se limitan a sugerencias

  • volver a una versión anterior de Java
  • violín con la configuración de memoria
  • uso de los clientes en lugar de modo de servidor

Volver a una versión anterior implica que el nuevo Java tiene un error, pero no he visto ninguna indicación de eso. La memoria no es un problema en absoluto; el servidor tiene 32 GB disponibles, y Xmx está configurado a 20, mientras que Xms es 10. No veo que la JVM se quede sin los 12 GB restantes (menos la cantidad otorgada a otros pocos procesos en la máquina). Y estamos atrapados con el modo de servidor debido a la naturaleza de la aplicación y el entorno.

Cuando miro la memoria y el uso de la CPU para la aplicación, veo uso de memoria constante durante todo el día, pero de repente justo antes de que muera el uso de la CPU aumenta al 100% y el uso de memoria va de X a X + 2GB, a X + 4GB, a (a veces) X + 8GB, a la muerte de JVM. Parece que tal vez haya un ciclo de ajuste de matriz repetido en la compilación de JIT.

Ahora he visto que se produce el error con la solicitud de 8GB anterior y también las solicitudes de 16 GB. En todos los casos, el método que se compila cuando esto sucede es el mismo. Es un método simple que tiene bucles no anidados, sin recurrencia, y utiliza métodos en objetos que devuelven campos de miembros estáticos o campos de miembros de instancias directamente con pocos cálculos.

así que tengo 2 preguntas:

  1. ¿Alguien tiene alguna sugerencia?
  2. ¿Puedo probar si hay un problema al compilar este método específico en un entorno de prueba, sin ejecutar toda la aplicación, invocando el compilador JIT directamente? ¿O debería iniciar la aplicación y decirle que compile métodos después de un recuento de llamadas mucho más pequeño (como 2) para obligarlo a compilar el método casi instantáneamente en lugar de en un punto aleatorio del día?

@StephenC

La JVM es 1.6.0_20 (anteriormente 1.6.0_0), que se ejecuta en Solaris. Sé que es la compilación la que está causando un problema por un par de razones.

  1. ps en los segundos que conducen a ella muestra que un hilo de java con id correspondiente a la rosca compilador (de jstack) está tomando el 100% del tiempo de CPU
  2. jstack muestra el problema está en JavaThread "CompilerThread1" daemon [_thread_in_native, id=34, ...]

El método mencionado en jstack es siempre el mismo, y es uno que escribimos. Si observa el resultado de la muestra jstack sabrá a qué me refiero, pero por razones obvias no puedo proporcionar ejemplos de código o nombres de archivo. Diré que es un método muy simple. Essentiall un puñado de comprobaciones nulas, 2 para bucles que hacen controles de igualdad y posiblemente asignar valores, y algunas llamadas a métodos simples después.Con todo, tal vez 40 líneas de código.

Este problema ha sucedido 2 veces en 2 semanas, aunque la aplicación se ejecuta todos los días y se reinicia diariamente. Además, la aplicación no estaba bajo carga pesada en ninguno de estos momentos.

+0

Sería útil si dijera qué versión de JVM y nivel de parche está utilizando (y qué era antes) y cuál es su plataforma de sistema operativo/hardware. Además, por qué ha concluido que el problema está sucediendo durante la compilación de JIT, cómo ha descubierto el método que se está compilando ... y cómo se ve el código del método. –

+0

¿Encontró una solución satisfactoria? –

+0

Lo siento por la * muy * respuesta tardía: he marcado la respuesta ahora – Phil

Respuesta

1

Bien, hice una búsqueda rápida y encontré un hilo en sun java forums that discusses esto. Espero eso ayude.

+0

Sí, eso también lo vi. Su problema es correr en contra de la memoria que queda en una sola asignación. Estoy viendo múltiples redistribuciones de array donde no debería haber ninguna. No hay ninguna razón para que compilar un método requiera 16 GB de memoria, ¿verdad? – Phil

+0

Entonces probablemente también haya probado las sugerencias que ha mencionado en su pregunta. ¿Alguno de esos trabajo? – naikus

1

Aquí otra entry on Oracles forum. Choque esporádico similar. Hay una respuesta en la que se resuelve el problema reconfigurando la proporción de supervivientes del gc.

5

Puede excluir un método particular de ser JIT creado creando un archivo llamado .hotspot_compiler y colocándolo en el directorio de trabajo de sus aplicaciones. Basta con añadir una entrada en el archivo con el siguiente formato:

exclude com/amir/SomeClass someMethod 

Y la salida de la consola del compilador se verá así:

### Excluding compile: com.amir.SomeClasst::someMethod 

Para obtener más información, lea this. Si no está seguro de cuáles son sus aplicaciones 'directorio de trabajo', use

-XX:CompileCommandFile=/my/excludefile/location/.hotspot_compiler 

en su script de inicio de Java o en la línea de comandos.

Alternativamente, si no está seguro de que los compiladores JIT tienen un error, y quiere ver si puede reproducir el problema sin ningún JIT'ing, ejecute su proceso de Java con -Xint.