2011-05-12 13 views
6

Tengo un problema muy extraño con una aplicación Java que se ejecuta bajo Tomcat.Depuración de una pérdida de memoria extraña - Java/Tomcat

Intentamos actualizar el código de producción de un recién producido en un sprint de 1 semana, la aplicación ha estado funcionando durante meses sin interrupciones y luego este nuevo código hace que nuestros servidores Linux comiencen a intercambiarse después de un tiempo.

Lo más extraño es que cuando se mira a VisualVM para el uso de memoria, nunca excede el tamaño máximo de almacenamiento dinámico, la JVM no arroja un OutOfMemory, la máquina solo comienza a intercambiar y la JVM sigue ejecutándose incluso después.

Parece que está perdiendo memoria de algún lado, parece que proviene del nuevo código pero es extraño que no esté dentro de la JVM, ¿alguna idea sobre cómo depurar eso?

Gracias!

+0

Puede ser útil mostrar el código. – soandos

+0

Cualquier código nativo involucrado (ya sea a través de JNI o ​​JNA), o es este puro Java? – QuantumMechanic

+0

¿Podría ser debido a archivos mapeados en memoria? ¿Qué muestra 'top' para el uso de memoria del proceso' java'? –

Respuesta

2

El intercambio no es un indicador concluyente de fuga. Es el resultado de una memoria física baja. Use vmstat en Linux para obtener el uso de intercambio. Intente utilizar una máquina diferente, experimente con las configuraciones --swap size, tamaño de la memoria física, espacio de direcciones.

Si está seguro de que el problema está en su programa intente esto:

  1. Estimación de la mediana y la memoria de pico que su uso debe programa . Debe poder dar cuenta de todas las desviaciones de estas métricas. Si no puede, continúe con el paso 3.

  2. Suponiendo que realizó correctamente el paso 1 y pudo dar cuenta de todas las desviaciones, puede descartar la fuga (disculpe las sugerencias tan vagas, pero la depuración solo es tan buena como el detective) Ahora debería centrarse en la sintonización de GC. Primero, habilite el registro GC. Vea si su montón está realmente lleno y dónde el GC está pasando la mayor parte del tiempo recolectando. This puede ser un buen punto de partida para comenzar las optimizaciones. Intenta ver si el ajuste de las opciones de GC te ayuda. Intente experimentar con algoritmos de recopilación, tamaños máximos/mínimos de almacenamiento dinámico, relaciones genéticas, etc. Solo experimente cuando haya descartado una fuga (paso 1).

  3. Suponiendo que realizó correctamente el paso 1 y no pudo tener en cuenta todas las desviaciones, puede suponer que tiene una pérdida en algún lugar. Utilice un generador de perfiles de memoria para ver qué objetos contribuyen más al crecimiento del tamaño de pila. Deje un generador de perfiles en ejecución durante un período prolongado de tiempo: haga que su programa maneje algunas solicitudes que rutinariamente espera obtener y luego déjelo relativamente aislado después de eso. Si el nivel de memoria sigue creciendo, es posible que haya una fuga en alguna parte. Si no, entonces probablemente no sea una pérdida de memoria. ¿Puedes señalar la parte de tu programa que puede estar creando? En caso afirmativo, intente enviar varias solicitudes que solo se dirijan a esa parte de su programa. ¿Replica el problema de manera determinista? Si no, repita el paso 3. En caso afirmativo, utilice dividir y conquistar y vuelva a aplicar el paso 3 hasta que pueda encontrar la clase/método que son los culpables. También puede ser una cierta combinación de porciones múltiples (lo que significa que individualmente pueden parecer inocentes, pero juntos pueden formar un sindicato del crimen brillante).

Espero que esto ayude, si no, por favor deja un comentario en mi post.

¡Todo lo mejor en su ejercicio!

+0

Muchas gracias por este paso a paso ... Es todo lo que sé que debe hacerse, pero debo recordarlo de vez en cuando. Estaba cansado de la depuración de la semana pasada y no tenía la mentalidad de comenzar a depurar de esta manera, actualmente lo estoy buscando y buscando si realmente es una filtración en la aplicación o en otro lugar del sistema operativo. – victorcampos

+0

Oye, no hay problemas. –

1

Le sugiero que busque crear volcados de almacenamiento dinámico sin usar jvisualvm. Para las JVM de Oracle basadas en Unix esto normalmente se hace enviando una señal 3 a la JVM usando kill.

Para más detalles ver http://www.startux.de/index.php/java/45-java-heap-dumpyvComment45

A continuación, puede ver si los patrones de cambios.

Si no obtiene una idea de esto, esto puede deberse a que está almacenando una subcadena de una cadena original muy grande (que lleva la matriz de cadena subyacente), o porque se aferra al sistema operativo recursos como conexiones de bases de datos abiertas, etc.

¿Ha comprobado que el conjunto de conexiones se ve bien?

0

Si no lo está utilizando, le recomiendo que use visual VM version 1.3.2 y todos los complementos. Es un gran salto desde versiones anteriores.

¿Qué sucede con el espacio de la memoria perm?

¿Cuál es la configuración de memoria que está utilizando? Mínimo y máximo, por supuesto, pero ¿qué hay del tamaño del espacio permanente?