【问题标题】:java.lang.OutOfMemoryError: PermGen space on web app usagejava.lang.OutOfMemoryError:Web 应用使用的 PermGen 空间
【发布时间】:2011-07-01 06:20:32
【问题描述】:

我正在努力解决最近出现的 outOfMemory PermGen 问题。出现错误时保存的日志sn-ps之一:

java.lang.OutOfMemoryError: PermGen space
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
        at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.findClass(ModuleImpl.java:1872)
        at org.apache.felix.framework.ModuleImpl.findClassOrResourceByDelegation(ModuleImpl.java:720)
        at org.apache.felix.framework.ModuleImpl.access$300(ModuleImpl.java:73)
        at org.apache.felix.framework.ModuleImpl$ModuleClassLoader.loadClass(ModuleImpl.java:1733)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)

我增加了最大烫发大小-XX:MaxPermGen=128m 但这只是一个临时解决方案,因为我很确定我们在这里面临一些内存泄漏。我们应用程序的 Web 部分部署在 jetty (jsf + icefaces) 上。单击随机组件会增加使用的内存 - 我正在使用 jstat -gcold 监控它,几乎每次点击都意味着多 3-4kb。我已将 -XX:+TraceClassLoading 添加到 jvm 参数中,当 Web 用户界面上有任何操作时,会看到许多 sun.reflect.GeneratedConstructorAccessorsun.reflect.GeneratedMethodAccessor 被记录。当使用 99% 的 permgen 时,我还进行了堆转储。我使用 YourKit profiler 来分析堆。在类加载器选项卡中有 sun.reflect.DelegatingClassLoader 行的负载,每个行有 1 个类。什么可能导致内存不断增长?任何帮助将不胜感激。

提前致谢, 卢卡斯

【问题讨论】:

  • MaxPermGen 增加之前的值是多少?
  • JVM 使用其默认值 84mb。

标签: java jsf memory-leaks icefaces permgen


【解决方案1】:

首先,这与 JSF 没有特别的关系。与 webapp 的需求相比,你只是给你的 appserver 提供了太少的内存。对于在幕后使用良好反射镜头的所有其他框架,您都会遇到同样的问题(想想所有那些 EL 解析)。这可以是 JSF、Wicket、Spring-MVC 甚至是普通的 JSP/Servlet。只有在严重依赖 EL 解析器的基于组件的 Web 框架上机会更大,例如 JSF(和其他)。

此外,众所周知,当您过于频繁地(热)重新部署时,Tomcat(基于)服务器也可能导致此问题。通过以下链接了解它以及如何处理它:

【讨论】:

  • 我只是有一种奇怪的感觉,无论我将多少内存分配给永久代,它仍然能够将其阻塞——至少它的行为方式让我这么认为。应用程序部署后,permgen 的使用率为 60%。遍历所有组件(这样基本上所有类都已加载)将 permgen 使用率提高到 65% 左右。然后,在 squish 自动化测试的帮助下,我很容易将使用率提高到近 80%。我猜所有基于反射的加载类都是一种预期行为,只是不知道为什么它们没有被卸载。
  • 这些事情总是让我想知道:.NET 是否也有同样的痛苦?他们使用分代 GC 算法;他们的字符串是不可变的;他们有反思。他们感受到我们的痛苦吗?他们怎么办?我开发了一个部署在 WebLogic 上的应用程序,该应用程序不需要重新启动服务器:没有泄漏,没有连接丢失。应用服务器是唯一的区别吗?
  • @Lukasz:JSF 序列化会话中有限数量的视图(默认为 15,可通过上下文参数配置)。一旦你使用了所有可能的表达式,它就会很稳定。您只需要确保服务器有足够的内存可以使用。以 100 个并发用户的 JMeter 为例进行压力测试,以了解边界。 @Duffymo:我不知道 .NET 或 Weblogic,但我知道 IIS 基本上没有基于软件的内存限制,它基本上可以免费使用 Windows 可用的尽可能多的内存。 Weblogic 可能具有更高的默认内存限制(如 Glassfish)。
  • @Lukasz:归结为您拥有相对复杂的 JSF 视图,并且默认情况下 Tomcat 仅附带相对较低的内存限制。所有都只需要根据压力测试进行调整/调整。
【解决方案2】:

在 Sun JVM 上,对属性和方法的反射访问最初是通过通过 JNI 调用到 JVM 实现来执行的。如果 JVM 注意到一个方法或字段被反射访问了很多,它会生成字节码来做同样的事情——它称为“膨胀”的机制。这有一个初始速度命中,但之后运行速度大约快 20 倍。如果您进行大量反思,将是一个巨大的胜利。

该字节码存在于由 DelegatingClassLoader 实例创建的类中并占用 permgen 空间。如果这是一个问题,您可以通过将系统属性 sun.reflect.inflationThreshold 设置为 0(零)来关闭通货膨胀。

【讨论】:

    【解决方案3】:

    我建议使用Eclipse MAT 并关注this tutorial dedicated to permgen problems

    尽管 duffymo 注意到您在分析问题方面做得很好,但问题的根源似乎仍然未知。也许它只是组件之一,一些解析器(如 jwenting 建议的那样)或类似的。这个问题并不一定意味着您需要从堆栈中丢弃 JSF。

    【讨论】:

    • 我也尝试过 MAT,但这与 YourKit 显示的基本相同 - 大量 sun.reflect.DelegatingClassLoader 条目
    【解决方案4】:

    Permgen 问题通常是由某些进程执行大量 String.intern() 操作引起的。 一些 XML/HTML 生成器和解析器犯了这个罪。 先看看那里,你可能会很快找到罪魁祸首。

    【讨论】:

    • Out 应用程序不使用它们,也许某些第 3 方会使用它们 - 来看看,谢谢。
    【解决方案5】:

    首先,感谢您对此事进行了如此彻底的调查,并且更好地编写了您的问题。如果每个人都像你一样有才华和优秀的作家,世界(和这个网站)会变得更美好。

    我认为您已经找到了答案:我认为 JSF 及其对反射的使用是您的问题。

    这就是我避免像瘟疫一样避免 JSF 的原因之一。

    在我看来,JSF 是 Struts 的失败扩展。我认为 HTML/CSS/JavaScript/AJAX UI 与 JSF 一样强大,如果不是更多的话,而且对我的 JVM 的负担要少得多。 UI 调用服务并保持良好状态并与服务器端分开。

    【讨论】:

    • 谢谢,但是我们现在还太远了,甚至无法考虑更改 Web 框架。
    • 错误印象。 perm gen 问题在 JSF 出现之前就已经存在。 struts/tiles 1.x 系列有 permgen 泄漏。其他框架也是如此。有各种不同原因的文章。它们都指向的主要点之一是由于与其他类加载器工件的链接而无法 GBed 的孤立对象/类。因此,您会遇到鸡和蛋的问题,该问题会阻止类/对象被 GC 和内存泄漏。谷歌各种文章,看看您的代码或您使用的任何第三方代码是否“有罪”。 TIA
    • 不是错误的印象。当然,如果没有 JSF,perm gen 问题也会发生。我只是碰巧观察到一个特别糟糕的 JSF 实现,它可以用日晷来计时页面刷新。我建议像瘟疫一样避免它。我喜欢那些刚接触 SO 的人决定花时间在 1.5 年前的问题上做这样的愚蠢问题。
    猜你喜欢
    • 1970-01-01
    • 2014-08-23
    • 2011-09-04
    • 2013-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多