Blog de Antonio Manuel Muñiz

Desarrollo, Ingeniería y Calidad del Software

Archivos mensuales: agosto 2008

Memoria PermGen en aplicaciones Java

¿Qué es la memoria PermGen?, de forma resumida se trata de la memoria usada por la máquina virtual Java para almacenar el código estático de las aplicaciónes que corren en ella.

¿Es posible que tengamos problemas con este tipo de memoria?, pues si, sobre todo en aplicaciones web que corren sobre un contenedor JSP/Servlet. La excepción que encontraremos será:

java.lang.OutOfMemoryError: PermGen space

¿Cómo es posible si mi código solo ocupa 1 MB y el límite de memoria PermGen es por defecto 64MB?, si tenemos en cuenta que sólo las librerías usadas por el contenedor pueden ocupar entre 20 y 30 MB, entonces no es tan disparatado. De todas formas seguimos teniendo un margen bastante amplio (unos 30 MB), pero a los 20-30 MB anteriores tenemos que sumarle el tamaño de las librerías de las que depende nuestra aplicación (normalmente en WEB-INF/lib), que si nos descuidamos levemente pueden alcanzar los 20 MB. Llegados a este punto casi hemos alcanzado los 64 MB.

¿Pero la máquina virtual carga el código en memoria bajo demanda?, cierto, aunque hay situaciones en que el código demandado no es solamente el utilizado por nuestra aplicación, un ejemplo claro es el uso de un ORM como Hibernate o un framework como Spring.

¿Cómo puedo monitorizar la memoria PermGen usada por mi aplicación?, con JPS y JSTAT, se trata de dos pequeñas utilidades incluidas en el JDK. En primer lugar debemos conocer el identificador del proceso Java que queremos monitorizar, para ello:

~/Antonio$ jps
  227
  336 WrapperSimpleApp
  340 Jps

En mi caso tengo corriendo una instancia de Plexus corriendo en mi máquina que corresponde al proceso 336. Para consultar la memoria PermGen que esta utilizando:

~/Antonio$ jstat -gcpermcapacity 336
  PGCMN      PGCMX       PGC         PC      YGC   FGC    FGCT     GCT
  8192,0     65536,0     25600,0     25600,0  24     4    0,457    0,866

De todos los datos mostrados nos interesa (en KBytes): la primera columna, tamaño mínimo reservado para la memoria PermGen; la segunda columna, tamaño máximo; tercera columna, memoria ocupada actualmente.

Evidentemente, si PGC (tercera columna) se aproxima a PGCMX debemos incrementar el máximo para la memoria PermGen incluyendo la siguiente opción en la inicialización de la máquina virtual:

-XX:MaxPermSize=256m

En mi caso sería en el script de incialización de Plexus. Es importante notar que la memoria reservada por la máquina virtual inicialmente será la suma de la memoria de datos inicial (heap) y la memoria de instrucciones inicial (PermGen), y similar para la memoria máxima.

Existen herramientas más completas e intuitivas que JSTAT, como Lambda Probe, pero no siempre tenemos la posibilidad de desplegar una aplicación en el contenedor para monitorizar estos parámetros, y mucho menos tocar el script arranque.

Estrategias de integración continua

Desde mi punto de vista las tareas de integración continua en un proyecto deben seguir estrategias diferentes en función del momento en que se encuentre el proyecto.

En fases tempranas del desarrollo los tests suelen fallar, porque el test no es totalmente estable, porque los desarrolladores han modificado algo que afecta a algún test, o simplemente porque en estas fases se producen cambios de rumbo más o menos importantes en cuanto a desarrollo. En esta fase temprana nos interesa que la integración continua genere reportes y documentación con una frecuencia alta (por ejemplo, cada hora) de forma que pueda consultarse el estado de las pruebas, pero que solo “avise” (fallo en una tarea) cuando falla la compilación, y no cuando fallan las pruebas. Es normal que las pruebas fallen, están para eso, si no fallaran nunca no tendrían sentido (o estamos dejando pruebas en el tintero).

Ahora bien, una vez alcanzado aproximadamente el 60% del tiempo total del proyecto se supone que la aplicación es bastante estable y las pruebas deben satisfacerse con pulcritud, ya no es aceptable que se produzcan fallos, y si se producen, debe ser motivo de alerta. En este punto la estrategia de integración continua debe cambiar, la frecuencia de ejecución de pruebas y generación de reportes puede disminuir (por ejemplo, cada noche), la compilación debe mantenerse cada hora, y si una prueba falla sí debe generarse un error en integración continua y notificarlo debidamente.

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.