Esta semana hemos seguido diagnosticando errores de memoría. Y por fin hemos dado con la solución: ni goteo de memoria, ni Icefaces, ni JSF, ni nada. Al final el servidor se caía porque se quedaba sin memoria, pero memoria que necesitaba realmente.
Os preguntareis, ¿por qué no fue lo primero que probasteis (subir el limite máximo de memoria de la JVM con el parámetro -Xmx)? Y la respuesta es: por dos motivos, el primero que la aplicación está en producción de un cliente muy grande y no es tan fácil cambiar esos parámetros sin argumentar por qué. El segundo: que si no sabemos si es que necesita más memoria o es que tiene un goteo, no parece muy ético subir el parámetro y dejarlo correr.
Esto último tiene un nombre: solución de problemas/programación por coincidencia. Es una práctica que, lamentablemente, estoy harto de ver y que consiste en dar palos de ciego toqueteando todo hasta que funciona. Y cuando funciona "me olvido y tiro p'alante", sin saber realmente si se ha arreglado o no, ni por que se ha arreglado.
No lo hagais más, anda :-P.
En fin, al grano, al final el problema es que nos habían reservado 256MB para la JVM y, después de dar un OutOfMemoryError, analizando un volcado del heap de la JVM resulta que de 100MB de heap que teníamos disponibles (sí, los otros 156MB se los comía el servidor de aplicaciones él solito) 81MB estabán ocupados por la clase WebAppClassLoader. Efectivamente, nuestro WAR ocupa 50MB y el classloader se lo tiene que guardar casi entero en memoria (tened en cuenta que lo que más ocupa en una aplicación web suelen ser los JAR) porque almacena el contenido de cada .class en un array de bytes más otras cositas asociadas.
Conclusión: nos quedaban unos 19MB para ejecutar nuestra aplicación. Y eso habiendo cargado solo un 70% de las clases totales de la aplicación. Así que, la solución propuesta ha sido subir el limite a 512MB y seguir probando.
Yo tengo fe en que se solucione, pero si vuelve a fallar, volveremos a hacer más pruebas, y volveré a abrasaros con otro artículo ;-P.
Mostrando entradas con la etiqueta memory. Mostrar todas las entradas
Mostrando entradas con la etiqueta memory. Mostrar todas las entradas
12 de marzo de 2010
5 de marzo de 2010
Al final Icefaces no parece tener Alzheimer ;-)
En referencia a mi artículo anterior sobre memory leaks en Icefaces, ya he estado haciendo varias pruebas y no parece que haya ningún problema con la memoria e Icefaces. Lo único que he encontrado es que la memoria minima necesitada por Icefaces es directamente proporcional al número de threads que tiene Tomcat lanzados en un momento dado. Es decir, que cuanto más estresemos una aplicación Icefaces, más threads lanzará Tomcat, y más memoria consumirá la JVM.
Por lo demás, el uso de memoria es normal. Sí es cierto, como os comente, que refrescando cualquier página, cuando Icefaces tiene el com.icesoft.faces.concurrentDOMViews activado, el uso de memoria se dispara. Esto es debido a que Icefaces, por cada nuevo refresco, se crea un árbol nuevo de componentes JSF y lo guarda en sesión (si tenemos JSF configurado para que el árbol se guarde en sesión, claro).
Sin embargo, esta reserva de memoria se limpia al finalizar la sesión y, salvo que crezca muy deprisa o no se liberen las suficientes sesiones, no debería dar problemas puesto que es recuperada correctamente por el recolector de basura.
En cualquier caso, como parece que este asunto del goteo de memoria con la aplicación Icefaces nos va a seguir persiguiendo unos días más, os mantendré informados de futuras averiguaciones.
Por lo demás, el uso de memoria es normal. Sí es cierto, como os comente, que refrescando cualquier página, cuando Icefaces tiene el com.icesoft.faces.concurrentDOMViews activado, el uso de memoria se dispara. Esto es debido a que Icefaces, por cada nuevo refresco, se crea un árbol nuevo de componentes JSF y lo guarda en sesión (si tenemos JSF configurado para que el árbol se guarde en sesión, claro).
Sin embargo, esta reserva de memoria se limpia al finalizar la sesión y, salvo que crezca muy deprisa o no se liberen las suficientes sesiones, no debería dar problemas puesto que es recuperada correctamente por el recolector de basura.
En cualquier caso, como parece que este asunto del goteo de memoria con la aplicación Icefaces nos va a seguir persiguiendo unos días más, os mantendré informados de futuras averiguaciones.
26 de febrero de 2010
Buscando memory leaks en Java
Hoy comenzamos :-).
Llevo desde mediados de esta semana buscando alguna herramienta gratuita para poder diagnosticar un "memory leak" (lo voy a traducir por "goteo de memoria") en una aplicacion web Java que hemos desarrollado para un cliente y que se ejecuta en Tomcat.
La aplicacion utiliza JSF e Icefaces y me huele que el error tiene que estar relacionado con este bug de Icefaces: http://jira.icefaces.org/browse/ICE-3027. Ellos dicen que lo tienen arreglado en la 1.7.1, pero a mi me sigue pasando en la 1.7.2 y en la 1.8.
Es fácil de reproducir: te colocas en la pagina inicial, y le das al Ctrl+R como un poseso. Esto inmediatamente hace que suba el tamaño del heap (lo veo con la consola JMX de Java; otro día os cuento como) y se mantiene alto durante mucho tiempo. Luego, si dejamos a Tomcat tranquilo durante un buen rato y le volvemos a hacer otra petición, libera un montón de memoria del heap y se queda como al principio. Formalmente no es un "memory leak", puesto que la memoria se recupera, pero como tarda mucho en hacerlo, es bastante facil que, antes de que a Java le de tiempo a liberar la memoria, nos de un OutOfMemoryError.
Pero vayamos al grano. Como he dicho, llevo ya tres dias buscando una herramienta gratis para depurar el goteo de memoria y creo que por fin la he encontrado. Se llama Ariadna, y se puede descargar desde este enlace. Es muy sencillito de usar, solo hay que seguir estos pasos:
Que paséis buen fin de semana.
Llevo desde mediados de esta semana buscando alguna herramienta gratuita para poder diagnosticar un "memory leak" (lo voy a traducir por "goteo de memoria") en una aplicacion web Java que hemos desarrollado para un cliente y que se ejecuta en Tomcat.
La aplicacion utiliza JSF e Icefaces y me huele que el error tiene que estar relacionado con este bug de Icefaces: http://jira.icefaces.org/browse/ICE-3027. Ellos dicen que lo tienen arreglado en la 1.7.1, pero a mi me sigue pasando en la 1.7.2 y en la 1.8.
Es fácil de reproducir: te colocas en la pagina inicial, y le das al Ctrl+R como un poseso. Esto inmediatamente hace que suba el tamaño del heap (lo veo con la consola JMX de Java; otro día os cuento como) y se mantiene alto durante mucho tiempo. Luego, si dejamos a Tomcat tranquilo durante un buen rato y le volvemos a hacer otra petición, libera un montón de memoria del heap y se queda como al principio. Formalmente no es un "memory leak", puesto que la memoria se recupera, pero como tarda mucho en hacerlo, es bastante facil que, antes de que a Java le de tiempo a liberar la memoria, nos de un OutOfMemoryError.
Pero vayamos al grano. Como he dicho, llevo ya tres dias buscando una herramienta gratis para depurar el goteo de memoria y creo que por fin la he encontrado. Se llama Ariadna, y se puede descargar desde este enlace. Es muy sencillito de usar, solo hay que seguir estos pasos:
- Descargamos la ultima versión y la descomprimimos (en mi caso en el directorio d:\java\ariadna).
- Desplegamos la aplicación web que queramos probar en Tomcat.
- Editamos el fichero catalina.bat de Tomcat y añadimos al principio:
set PATH=%PATH%;d:/java/ariadna set CATALINA_OPTS=%CATALINA_OPTS% -agentlib:ariadna
- Echamos el fichero ariadna.jar que está en d:\java\ariadna en el directorio WEB-INF\lib de nuestra aplicación web.
- Ahora creamos una página JSP que colocaremos en el directorio raíz de nuestra aplicación web y que contendrá lo siguiente:
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<form method="get">
<input type="submit" name="button" value="Dump heap">
</form>
<%
if( "Dump heap".equals(request.getParameter("button")) ){
org.mernst.ariadna.agent.Agent.dump();
out.println( "Heap dumped on "+new java.util.Date() );
}
%>- A continuación, apuntamos el navegador a la página ariadna.jsp y le damos al botón. Nos saldra la misma página con el botón y un mensaje que dirá "Heap dumped on ...".
- ¿Qué hemos conseguido con esto? Pues que ahora en el directorio bin de Tomcat, tengamos dos ficheros con un volcado del contenido del heap. Dichos ficheros son heap y classes.txt. No os lanceis como locos a abrirlos aún ;-).
- Para ver el contenido de dichos ficheros, Ariadna nos proporciona una herramienta que arranca un servidor Jetty que nos permite visualizar los datos del heap desde un navegador. Para lanzar dicha herramienta solo tenemos que ir al directorio bin de Tomcat y ejecutar el siguiente comando:
java -jar d:/java/ariadna/ariadna.jar
- Como he dicho, esto arrancará un servidor Jetty, que escucha en el puerto 9999. Nos vamos al navegador, ponemos http://localhost:9999/classes en la barra de direcciones y ¡listos! ya tenemos el listado de clases cargadas, con el número de instancias de cada clase. Si pinchamos en una clase podremos ver todas sus instancias pudiendo, a su vez, pinchar en cada una de ellas para ver desde donde fueron reservadas.
Que paséis buen fin de semana.
Suscribirse a:
Entradas (Atom)