02 enero 2011

Jasper Reports -Virtualizar-

Hoy les contare sobre un problema que tuve durante estos días, estoy en el desarrollo de una aplicación constituida con Java para el lado servidor y Flex para el lado cliente, últimamente la aplicación había tenido unos problemas con el consumo de memoria luego de analizarla descubrí que esto era básicamente por dos motivos uno de ellos relacionados con Hibernate y el levantamiento de 60000 objetos en memoria lo cual al fin de cuentas lo termine resolviendo con NameQuery, pero aun tenía problemas cuando se ejecutaban varios reportes ya que la memoria del servidor subía inmesuradamente, a continuación les dejo la solución que encontré.


Antes que nada quiero recomendarles que cuando tengan un problema de memoria utilicen jVisualVM es un programa que te deja conectarte al servidor y ver la cantidad de instancias en memoria y así analizar cuál es la que se queda alocada o cuales consumen mucho, como primer paso use el programa y me conecte al servidor (Tomcat) y comencé a arrojar reportes al parecer el GC (Garbage Collector) corría de forma normal pero cuando había muchos reportes al mismo tiempo veía que la cantidad de instancia de JRTemplatePrintText crecía drásticamente.
Luego de investigar un poco encontré que Jasper Report durante su proceso de fill (Obtener los datos y rellenar la plantilla del informe con estos) levantaba los objetos en memoria, entonces la forma de abordar este problema es de dos maneras:
La paginación y la virtualización.
Paginación se refiere a obtener el informe en trozos, en lugar de recoger toda la información de golpe, pero como al final los datos se tienen que mostrar juntos en un único informe, nos introducen la virtualización. La virtualización es una técnica que consiste en serializar los datos, para no saturar la memoria heap.
Cabe aclarar que incluir virtualización conlleva la pérdida de rendimiento.

Aquí un ejemplo de cómo tendríamos que usar la virtualizacion:


JasperPrint jasperprint = null;
JRFileVirtualizer virtualizer = new JRFileVirtualizer(10, "tmp");

long start = System.currentTimeMillis();  

filterParameters.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);

jasperprint = JasperFillManager.fillReport(this.reportFile,this.filterParameters, this.databaseConnection);

virtualizer.setReadOnly(true);
logger.info("Filling time : " + (System.currentTimeMillis() - start));

// Usamos los exportadores para generar el reporte en lo que nosotros queramos.

virtualizer.cleanup();

Se vemos el ejemplo veremos que básicamente creamos un JasperPrint como lo haríamos normalmente pero al momento de generar este JasperPrint por medio del método fillReport de la clase JasperFillManager notamos que en los parámetros le pasamos un Virtualizer esto básicamente quiere decir que Jasper ira creando archivos temporales en la carpeta que le pasamos como segundo parámetro y el primer parámetro es usado para saber el tamaño máximo de los archivos, como ultima línea no debemos olvidar hacer un cleanup del virtualizer para borrar los archivos creados.

Bueno espero que este simple post les sirva como me sirvió a mí encontrar esta técnica para no malgastar memoria durante la generación de reportes ya sean medianos o grandes
Vale recordarles que deben tener en cuenta el balance entre performance y gasto de memoria esto lo pueden manejar con el tamaño máximo de los archivos.

Saludos,
Luis

Leer más...