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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12943030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 10:52:34  来源:igfitidea点击:

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

javaspringtomcatjasper-reportsjstl

提问by Dreamer

Our web application encounter a complicated situation

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

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:

它是由 STS/ 开发的 Spring 应用程序Tomcat 7。应用与 集成后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

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

这是异常中的一个部分,我发现了一些关于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
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()
0(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.

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

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

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

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

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

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

  1. The first question is even there is a jasperreport beanin 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.Digesteractually seems busy on parsing the jasper template?

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

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?

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

Apologize if too verbose, and thanks for any hints.

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

回答by Dreamer

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 !

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

As we know .jasperis a compiled template as well as .jrxmlis 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.

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

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

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

回答by shazinltc

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.

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

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

这篇文章对 java.lang.OutOfMemoryError: PermGen space error 有一个清晰的解释,下面的文章有关于如何修复它的建议。在 SO 上提出了一个类似(但不完全相同)的问题,如果您错过了,请告诉您。我希望它有帮助。

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

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

回答by sfxm

I have developed a web application which uses JasperReports 4.5.1

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

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

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

When shutdown the tomcat,it throw :

当关闭tomcat时,它抛出:

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.

Web 应用程序使用 [net.sf.jasperreports.engine.util.JRFontUtil$1] 类型的键(值 [net.sf.jasperreports.engine.util.JRFontUtil$1@7892f1])和类型 [java .util.HashSet](值 [[]]),但在 Web 应用程序停止时未能将其删除。这很可能造成内存泄漏。

Please visit the website:

请访问网站:

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

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

回答by jakub.petr

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

尝试在您的 VM 中设置这些参数。这些应该启用 GC 清理您的永久代。

##代码##

回答by Frank Pavageau

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

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

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

  • 检查 web 应用程序是否不包含(太多)无用的 jars,这些 jars 可能会因扫描而被加载

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



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

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

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.

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