OutOfMemoryError:PermGen Space – 在Tomcat上运行Spring的Jasper报告

我们的Web应用程序遇到了复杂的情况

它是由STS / Tomcat 7开发的Spring应用程序。 应用程序与Jasper report 4.6.0集成后,它总是抛出`OutOfMemoryError:PermGen Space。 然后,让它工作的唯一方法是重新启动应用程序。 但过了一段时间它又发生了。 这是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 

这是exception中的一节,我发现了一些关于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) 

情况发生时,以下是一些调查结果:

  1. 问题可能发生在页面上,没有任何Jasper Report组件。 似乎Jasper Report bean a request is processed by the back end and responded to the front end一直试图找到一个标记库。 通常从日志文件中我可以看到,在所有后端操作(JPA管理)完成之前,exception不会抛出

  2. 在调试模式下运行log4J时,我看到大量信息显示解析/呈现Jasper模板中的所有组件(文本字段,笔,框…),从巨大的日志中有一小部分:

     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() 

    但是,当对页面的请求不包含任何Jasper组件时,会生成此日志。

我做了一些研究,但仍无法找到解决这个问题的方法。

  1. 第一个问题是,即使在应用程序中有一个jasperreport bean ,当它甚至没有使用当前服务自动assembly时(因为当前页面没有任何jasper组件),它始终在运行。 有这种情况的解决方案/答案吗?

  2. 同样来自exception消息至少有一个JAR被扫描用于尚未包含TLD的TLD。 在org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:442)

    应该来自Tomcat, Tomcat never contains any JSTL jar ,然后我认为它无法找到匹配TLD来解析jasper报告,因此对所有jar进行全面扫描。 如果是这样,那么为什么来自org.apache.commons.digester.Digester大量调试日志实际上似乎忙于解析jasper模板?

一般来说,让这个线程只是试图找出问题的解决方案,并找到一个答案,为什么Jasper如此活跃在一个地方不需要它,以及我们如何让tomcat正确解析模板?

如果过于冗长,请道歉,并感谢任何提示。

谢谢大家为这个问题提供解决方案,我已经根据我的情况确定了问题,这是解决方案:

使用.jasper而不是.jrxml作为模板!

我们知道.jasper是一个编译模板,而.jrxml是模板的ASCII源代码,所以如果我们在当前spring应用程序中使用原始源代码文件(jrxml)作为模板,那么至少spring框架工作必须编译源代码代码文件。 这是一个留给Spring框架的效率问题,因为它是处理编译的jasper bean,并且不能保证编译只执行一次并且只在应用程序启动时才会发生。

简而言之,在用.jasper文件替换所有模板后,日志大小已经大大减少,并且还没有看到内存不足的问题。 我猜Spring容器可能会消耗大量资源来在运行时将jrxml编译为jasper。 所以它可能是贾斯珀或spring应该改进的东西….

当JVM中的permgen空间中存在太多.class文件时,会发生exception,由于它对AppClassLoader外部的对象的引用而无法进行垃圾回收。 它通常指出一些内存泄漏您的applciation。

这篇文章清楚地解释了java.lang.OutOfMemoryError:PermGen空间错误,以下post提供了有关如何修复它的建议。 在SO上问了一个类似的(但不完全相同的) 问题 ,让你知道你是否错过了它。 我希望它有所帮助。

正如jakub提到设置-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled或为XX:MaxPermSize设置更高的值XX:MaxPermSize可能适合您。 但据我所知,它似乎不是一个永久的解决方案。 (我不是这里的主人:))。

尝试在VM中设置这些参数。 这些应该使GC能够清洁你的permGen。

 -XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled 

我开发了一个使用JasperReports 4.5.1的Web应用程序

我使用Tomcat 6.0.26作为容器。 (Win7,JDK 1.6.0_25)

当关闭tomcat时,它抛出:

Web应用程序创建了一个ThreadLocal,其键为[net.sf.jasperreports.engine.util.JRFontUtil $ 1](值[net.sf.jasperreports.engine.util.JRFontUtil$1@7892f1]),类型为[java] .util.HashSet](值[[]])但在Web应用程序停止时无法将其删除。 这很可能造成内存泄漏。

请访问网站:

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

由于PermGen主要包含类元数据,以及常量和实体字符串,因此您可以在两个方向上搜索:

  • 检查webapp是否包含(太多)无用的jar,这些jar可能因扫描而加载

  • 看看你是否有很多使用堆转储的常量字符串(例如很多大型JSP),或者你的代码是否使用了String.intern()


实际上,您没有指定您使用的Java版本:使用Java 7时,String可能不是问题。

你可以做的是用JVisualVM观察应用程序,使用VisualGC插件,查看代的状态,加载的类的数量以及在OOM时是否有激增,或者它是否是一个缓慢的构建-up。