8

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.

Dreamer
  • 7,333
  • 24
  • 99
  • 179
  • So, have you tried increasing the size of the PermGen? It's not like there are many other ways. – Frank Pavageau Oct 17 '12 at 20:52
  • @Frank Pavageau yes I tried, put it to 512M but still get the same issue...is it in the `catalina.sh` and JAVA_OPTS="...-XX:MaxPermSize=512m..." ? – Dreamer Oct 17 '12 at 20:58
  • 1
    @FrankPavageau it seems jasper reports have these kind of issues with some configurations, so troubleshooting the root cause in jasper reports might very well be feasible. – eis Oct 17 '12 at 21:14
  • @eis please enlighten me about how to trace the root cause in Jasper Report or I should try HeapDumpOnOutOfMemoryError ? Thanks. – Dreamer Oct 17 '12 at 21:20
  • @Dreamer try that, getting a heap dump of the error condition and analyzing that should be a step forwards – eis Oct 18 '12 at 08:23

5 Answers5

9

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....

Dreamer
  • 7,333
  • 24
  • 99
  • 179
7

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 :)).

Community
  • 1
  • 1
shazinltc
  • 3,616
  • 7
  • 34
  • 49
2

Try setting these parameters in your VM. These should enable GC cleaning your permGen.

-XX:+UseConcMarkSweepGC
-XX:+CMSPermGenSweepingEnabled
-XX:+CMSClassUnloadingEnabled
jakub.petr
  • 2,951
  • 2
  • 23
  • 34
  • Thank you. Are you sure we do this to the JVM not Tomcat? Is there performance impact by this change? – Dreamer Oct 17 '12 at 21:10
  • The PermGen OOM usually occurs _because_ the GC ran but could not free memory, not because the GC is not taking care of the PermGen. – Frank Pavageau Oct 17 '12 at 21:10
  • 1
    to actually diagnoze what is the problem, you should add also `-XX:+HeapDumpOnOutOfMemoryError` so you would get a heap dump. Unsure if it works on permgen error, but I would recommend to try. That heap dump should then be run through with MAT or similar. – eis Oct 17 '12 at 21:11
  • Yes, you should set these in Tomcat configuration, so when it starts VM for your apps than it starts with these parameters. We are using these with GlassFish and didn't notice any performance impact, just PermGen error stopped showing up. – jakub.petr Oct 17 '12 at 21:13
2

I have developed a web application which uses JasperReports 4.5.1

I use Tomcat 6.0.26 as a container. (Win7, JDK 1.6.0_25)

When shutdown the tomcat,it throw :

The web application created a ThreadLocal with key of type [net.sf.jasperreports.engine.util.JRFontUtil$1] (value [net.sf.jasperreports.engine.util.JRFontUtil$1@7892f1]) and a value of type [java.util.HashSet] (value [[]]) but failed to remove it when the web application was stopped. This is very likely to create a memory leak.

Please visit the website:

http://community.jaspersoft.com/questions/534340/memory-leak-jr-373

sfxm
  • 131
  • 1
  • 5
0

Since the PermGen mainly contains class metadata, and constant and interned Strings, you can search in two directions:

  • check that the webapp does not contain (too many) useless jars, which might get loaded due to scanning

  • see if you have lots of constant Strings (lots of large JSPs, for example) using a heap dump, or if your code uses String.intern()


Actually, you did not specify which version of Java you were using: with Java 7, the String might not be an issue.

What you could do is to observe the application with JVisualVM, using the VisualGC plugin, to see the state of the generations, the number of loaded classes and whether there's a surge in either at the time of the OOM, or if it's a slow build-up.

Frank Pavageau
  • 11,477
  • 1
  • 43
  • 53