【问题标题】:OutOfMemoryError: PermGen Space -- Jasper Report with Spring running on TomcatOutOfMemoryError: PermGen Space -- Jasper Report with Spring 在 Tomcat 上运行
【发布时间】:2012-10-08 05:24:21
【问题描述】:

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

是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 报告组件的页面上。当a request is processed by the back end and responded to the front end 时,Jasper Report bean 似乎一直在尝试查找标记库。通常从日志文件中我可以看到,在所有后端操作(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 组件的页面的请求时,会生成此日志。

我做了一些研究,但仍然找不到解决此问题的方法。

  1. 第一个问题是即使应用程序中有一个jasperreport bean,为什么它甚至没有与当前服务自动连接时它总是在运行(意味着当前页面没有任何碧玉组件)。这种情况有解决方案/答案吗?

  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 模板?

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

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

【问题讨论】:

  • 那么,您是否尝试过增加 PermGen 的大小?好像没有很多其他的方法。
  • @Frank Pavageau 是的,我试过了,将其设置为 512M,但仍然遇到同样的问题...是在 catalina.sh 和 JAVA_OPTS="...-XX:MaxPermSize=512m 中吗? ." ?
  • @FrankPavageau 似乎 jasper 报告的某些配置存在此类问题,因此排除 jasper 报告中的根本原因很可能是可行的。
  • @eis 请告诉我如何在 Jasper Report 中追踪根本原因,或者我应该尝试 HeapDumpOnOutOfMemoryError 吗?谢谢。
  • @Dreamer 尝试一下,获取错误情况的堆转储并分析这应该是向前迈出的一步

标签: java spring tomcat jasper-reports jstl


【解决方案1】:

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

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

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

简而言之,将所有模板替换为 .jasper 文件后,日志大小已显着减小,并且不再出现内存不足的问题。我猜 Spring 容器在运行时可能会消耗大量资源来将 jrxml 编译为 jasper。所以它可能是 Jasper 或 Spring 应该改进的东西......

【讨论】:

    【解决方案2】:

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

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

    正如 jakub 提到的那样,设置 -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled 或为 XX:MaxPermSize 设置更高的值可能对您有用。但从我所阅读的内容来看,这似乎不是一个永久的解决方案。 (我不是这方面的大师 :))。

    【讨论】:

    • 链接上的帖子不错。如果有人需要了解正在发生的事情,最好阅读这些帖子。谢谢。
    【解决方案3】:

    尝试在您的虚拟机中设置这些参数。这些应该能够让 GC 清理你的 permGen。

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

    【讨论】:

    • 谢谢。您确定我们对 JVM 而不是 Tomcat 执行此操作吗?此更改是否会影响性能?
    • PermGen OOM 通常发生因为 GC 运行但无法释放内存,而不是因为 GC 没有处理 PermGen。
    • 要真正诊断出问题所在,您还应该添加-XX:+HeapDumpOnOutOfMemoryError,这样您就可以获得堆转储。不确定它是否适用于 permgen 错误,但我建议尝试一下。然后应该使用 MAT 或类似方法运行该堆转储。
    • 是的,您应该在 Tomcat 配置中设置这些,因此当它为您的应用程序启动 VM 时,它会以这些参数启动。我们将这些与 GlassFish 一起使用,并没有发现任何性能影响,只是 PermGen 错误停止出现。
    【解决方案4】:

    我开发了一个使用 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

    【讨论】:

      【解决方案5】:

      由于 PermGen 主要包含类元数据,以及常量和内部字符串,您可以从两个方向搜索:

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

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


      实际上,您没有指定您使用的 Java 版本:对于 Java 7,字符串可能不是问题。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-03
        • 1970-01-01
        • 2011-12-14
        • 2012-04-02
        • 2016-03-29
        • 1970-01-01
        • 2012-11-25
        • 2013-03-08
        相关资源
        最近更新 更多