Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OutOfMemoryError: PermGen Space -- Jasper Report with Spring running on Tomcat

Our web application encounter a complicated situation

It is a Spring application developed by STS/Tomcat 7. After the application been integrated with Jasper report 4.6.0, it always throw `OutOfMemoryError: PermGen Space. Then the only way to get it work is to restart the application. But after a while it happen again. Here is log before the exception:

Oct 17, 2012 3:42:27 PM org.apache.jasper.compiler.TldLocationsCache tldScanJar
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Oct 17, 2012 3:42:30 PM org.apache.catalina.core.ApplicationDispatcher invoke
SEVERE: Servlet.service() for servlet jsp threw exception

Here is a section within the exception where I found something about Jasper:

at org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:442)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:378)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:353)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:340)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:646)
at org.apache.jasper.servlet.JspServletWrapper.loadTagFile(JspServletWrapper.java:240)
at org.apache.jasper.compiler.TagFileProcessor.loadTagFile(TagFileProcessor.java:578)
at org.apache.jasper.compiler.TagFileProcessor.access$000(TagFileProcessor.java:49)
at org.apache.jasper.compiler.TagFileProcessor$TagFileLoaderVisitor.visit(TagFileProcessor.java:655)

Here are a few findings when the situation occurs:

  1. The issue can happen on page without any Jasper Report components. It seems the Jasper Report bean is trying to find a tag lib all the time when a request is processed by the back end and responded to the front end. Normally from log file I can see above exception will not throw until all back end operations(JPA management) are complete

  2. When run log4J on debug mode, I see tons of information showing something like parsing/rendering the all components from Jasper template(textfields, pen, box...), there is a small cut from the huge log:

    2012-10-17 15:29:12,025 -- DEBUG -- org.apache.commons.digester.Digester.sax -- startElement(http://jasperreports.sourceforge.net/jasperreports,textElement,textElement)
    2012-10-17 15:29:12,025 -- DEBUG -- org.apache.commons.digester.Digester --   Pushing body text ''
    2012-10-17 15:29:12,025 -- DEBUG -- org.apache.commons.digester.Digester --   New match='jasperReport/summary/band/textField/textElement'
    2012-10-17 15:29:12,025 -- DEBUG -- org.apache.commons.digester.Digester --   Fire begin() for FactoryCreateRule[className=net.sf.jasperreports.engine.xml.JRTextElementFactory, attributeName=null, creationFactory=net.sf.jasperreports.engine.xml.JRTextElementFactory@12dc6007]
    2012-10-17 15:29:12,025 -- DEBUG -- org.apache.commons.digester.Digester -- [FactoryCreateRule]{jasperReport/summary/band/textField/textElement} New net.sf.jasperreports.engine.design.JRDesignTextField
    2012-10-17 15:29:12,025 -- DEBUG -- org.apache.commons.digester.Digester.sax -- ignorableWhitespace()
    

    Still, this log is generated when a request to the page which does not contains any Jasper component.

I did some research but still cannot find the solution to this issue.

  1. The first question is even there is a jasperreport bean in the application why it is always running when it is not even autowired with current service(meaning current page doesn't have any jasper component). Is there a solution/answer to this situation?

  2. Also from the exception message At least one JAR was scanned for TLDs yet contained no TLDs. at org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:442)

    should comes from Tomcat, and Tomcat never contains any JSTL jar, then I assume it cannot find a match TLD to parse jasper report hence do a full scan of all jars. If so, then how come there is huge amount of debug logs from org.apache.commons.digester.Digester actually seems busy on parsing the jasper template?

In general, make this thread is just try to figure out a solution to the probelm, and also find an answer to why Jasper is so active on a place doesn't require it, and how we can let tomcat properly parsed the templates?

Apologize if too verbose, and thanks for any hints.

like image 483
Dreamer Avatar asked Oct 17 '12 20:10

Dreamer


People also ask

How to resolve PermGen space error in tomcat?

Solution By default, Tomcat is assigned a very little PermGen memory for the running process. To fix it, increase the PermGen memory settings by using the following Java VM options. -XX:PermSize<size> - Set initial PermGen Size. -XX:MaxPermSize<size> - Set the maximum PermGen Size.

How can I increase my PermGen size?

The default maximum memory size for 32-bit JVM is 64 MB and 82 MB for the 64-bit version. However, we can change the default size with the JVM options: -XX:PermSize=[size] is the initial or minimum size of the PermGen space. -XX:MaxPermSize=[size] is the maximum size.


2 Answers

Thank you everyone for giving solution about this issue, I have identified the problem specifically to my situation and here is the solution:

Use .jasper instead of .jrxml as template !

As we know .jasper is a compiled template as well as .jrxml is ASCII source code for the template, so if we use raw source code file (jrxml) as template in current spring application then at least spring frame work has to compile the source code file. That's a question of efficiency left to Spring framework as it is the jasper bean to handle the compilation and it is not guaranteed the compilation executed only once and only happens when the application starting.

In short, after replace all templates with .jasper file, the log size has been significantly reduced and haven't seen the out of memory issue any more. I guess Spring container may be consume a lot of resource to compile jrxml to jasper at runtime. So it could be something should've improved by Jasper or Spring....

like image 122
Dreamer Avatar answered Nov 03 '22 09:11

Dreamer


The exception occurs when there are too many .class files in the permgen space in the JVM which cannot be garbage collected due to its references to an object outside the AppClassLoader. It generally points out to some memory leak your applciation.

This post has a lucid explanation of java.lang.OutOfMemoryError: PermGen space error and a following post has suggestions on how to fix it. A similiar (but not exactly the same) question was asked on SO, letting you know if you missed it. I hope it helps.

As jakub has mentioned setting -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled or setting a higher value for XX:MaxPermSize might work for you. But from what I have read, it isn't a permanent solution it seems. (I am not a master in this :)).

like image 37
shazinltc Avatar answered Nov 03 '22 10:11

shazinltc