xmn - set java memory
Error de JVM OutOfMemory "muerte en espiral"(no pérdida de memoria) (6)
- Sí, he observado este comportamiento antes y, por lo general, después de innumerables horas de ajustar los parámetros de la JVM, comienza a funcionar.
- La recolección de basura, especialmente en situaciones de multiproceso no es determinista. Definir un error en un código no determinista puede ser un desafío. Pero puede probar DTrace si está usando Solaris, y hay muchas opciones de JVM para mirar en HotSpot.
- Ir a Scala IRC y ver si Ismael Juma está merodeando (ijuma). Él me ha ayudado antes, pero creo que una verdadera ayuda en profundidad requiere pagarlo.
- Creo que la mayoría de las personas que hacen este tipo de cosas aceptan que necesitan ser expertos en ajuste de JVM, tener uno en el personal o contratar un consultor. Hay personas que se especializan en afinar JVM.
Para resolver estos problemas, creo que necesita poder replicarlos en un entorno controlado donde puede duplicar de forma precisa las ejecuciones con diferentes parámetros de ajuste y / o cambios de código. Si no puede hacer eso, contratar a un experto probablemente no le hará ningún bien, y la forma más económica de solucionar el problema es probablemente comprar más RAM.
Recientemente hemos estado migrando una serie de aplicaciones de RedHat linux JDK1.6.0_03 a Solaris 10u8 JDK1.6.0_16 (máquinas con muchas más especificaciones) y hemos notado lo que parece ser un problema bastante urgente: bajo ciertas cargas nuestros JVMs ellos mismos en una "Espiral de la Muerte" y eventualmente se quedan sin memoria. Cosas a tener en cuenta:
- Este no es un caso de una pérdida de memoria . Estas son aplicaciones que han estado funcionando bien (en un caso por más de 3 años) y los errores de falta de memoria no son seguros en ningún caso. A veces las aplicaciones funcionan, otras no.
- No nos estamos moviendo a una máquina virtual de 64 bits , todavía estamos ejecutando 32 bits
- En un caso, el uso del último recolector de basura G1 en 1.6.0_18 parece haber resuelto el problema. En otro, volver a 1.6.0_03 ha funcionado.
- A veces nuestras aplicaciones se caen con los errores HotSpot
SIGSEGV
- Esto está afectando a las aplicaciones escritas en Java, así como Scala
El punto más importante es este: el comportamiento se manifiesta en aquellas aplicaciones que repentinamente obtienen una avalancha de datos (generalmente a través de TCP) . Es como si la VM decidiera seguir agregando más datos (posiblemente progresándolos al TG) en lugar de ejecutar un GC en el "espacio de noticias" hasta que se dé cuenta de que tiene que hacer un GC completo y luego, a pesar de que prácticamente todo en la VM es basura. , de alguna manera decide no recogerlo!
Suena loco, pero simplemente no veo qué más es. ¿De qué otra manera puede explicar una aplicación que un minuto se cae con un montón máximo de 1Gb y el siguiente funciona bien (nunca va a unos 256M cuando la aplicación está haciendo exactamente lo mismo )?
Así que mis preguntas son:
- ¿Alguien más ha observado este tipo de comportamiento?
- ¿Alguien tiene alguna sugerencia sobre cómo podría depurar la JVM en sí (a diferencia de mi aplicación)? ¿Cómo pruebo que esto es un problema de VM?
- ¿Hay algún foro especializado en máquinas virtuales por ahí donde pueda preguntar a los autores de la máquina virtual (suponiendo que no estén en SO)? (No tenemos contrato de soporte)
- Si se trata de un error en las últimas versiones de la máquina virtual, ¿por qué nadie más lo ha notado?
¿Qué tipo de OutOfMemoryError está obteniendo? ¿Se ha agotado el espacio del montón o está relacionado el problema con cualquiera de los otros grupos de memoria (el error generalmente tiene un mensaje que proporciona más detalles sobre su causa)?
Si el montón está agotado y el problema se puede reproducir (suena como si fuera posible), en primer lugar configuraría la VM para producir un volcado de pila en OutOfMemoryErrors. Luego puede analizar el montón y asegurarse de que no esté lleno de objetos, a los que aún se puede acceder mediante algunas referencias inesperadas.
Por supuesto, no es imposible que se esté ejecutando un error de VM, pero si su aplicación se basa en un comportamiento específico de la implementación en 1.6.0_03, puede, por algún motivo u otro, convertirse en un montón de memoria cuando se ejecuta en 1.6.0_16. Estos problemas también se pueden encontrar si está utilizando algún tipo de contenedor de servidor para su aplicación. Algunos desarrolladores obviamente no pueden leer la documentación, pero tienden a observar el comportamiento de la API y a sacar sus propias conclusiones acerca de cómo se supone que funciona algo. Por supuesto, esto no siempre es correcto y me he encontrado con problemas similares con Tomcat y con JBoss (ambos productos, al menos, se utilizan para trabajar solo con máquinas virtuales específicas).
¿Qué tipo de errores SIGSEV encuentra exactamente?
Si ejecuta una máquina virtual de 32 bits, podría ser lo que describí aquí: http://janvanbesien.blogspot.com/2009/08/mysterious-jvm-crashes-explained.html
He tenido el mismo problema en las máquinas Solaris y lo resolví reduciendo el tamaño máximo de la JVM. La implementación de Solaris de 32 bits aparentemente necesita algo de espacio adicional más allá de lo que asigna para la JVM al realizar recolecciones de basura. Entonces, por ejemplo, con -Xmx3580M
obtendría los errores que describe, pero con -Xmx3072M
estaría bien.
Problema interesante. Parece que uno de los recolectores de basura funciona mal en su situación particular.
¿Has intentado cambiar el recolector de basura que se está utilizando? Hay MUCHAS opciones de GC, y descubrir cuáles son las óptimas parece ser un poco de arte negro, pero me pregunto si un cambio básico funcionaría para ti.
Sé que hay un GC "Servidor" que tiende a funcionar mucho mejor que los predeterminados. ¿Estás usando eso?
El GC roscado (que creo que es el predeterminado) es probablemente el peor para su situación particular, he notado que tiende a ser mucho menos agresivo cuando la máquina está ocupada.
Una cosa que he notado, a menudo se necesitan dos GC para convencer a Java de que realmente saque la basura. Creo que el primero tiende a desvincular un montón de objetos y el segundo en realidad los elimina. Lo que quizás quieras hacer es forzar ocasionalmente dos recolecciones de basura. Esto provocará una pausa significativa en la GC, pero nunca he visto un caso en el que se necesitaran más de dos para limpiar todo el montón.
También asegúrese de que no sea un fallo de hardware (intente ejecutar MemTest86 o similar en el servidor).