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

时间:2012-10-17 20:42:05

标签: java spring tomcat jasper-reports jstl

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

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

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

以下是异常中我发现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管理)完成之前,异常不会抛出

  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组件时,会生成此日志。

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

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

    2. 同样来自异常消息      至少有一个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模板?

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

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

5 个答案:

答案 0 :(得分:8)

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

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

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

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

答案 1 :(得分:7)

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

This帖子对java.lang.OutOfMemoryError有一个清晰的解释:PermGen空间错误和以下post有关于如何修复它的建议。 在SO上问了一个类似的(但不完全相同的)question,让你知道你是否错过了它。我希望它有所帮助。

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

答案 2 :(得分:2)

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

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

答案 3 :(得分:2)

我开发了一个使用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](value [[]])但在Web应用程序停止时无法将其删除。 这很可能会造成内存泄漏。

请访问网站:

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

答案 4 :(得分:0)

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

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

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


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

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

相关问题