问题 java.lang.OutOfMemoryError:Web应用程序使用的PermGen空间


我正在努力解决最近出现的outOfMemory PermGen问题。出现错误时保存的其中一个日志片段:

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 params并看到很多 sun.reflect.GeneratedConstructorAccessor 和 sun.reflect.GeneratedMethodAccessor 在Web用户界面上有任何操作时被记录。当使用99%的permgen时,我也进行了堆转储。我使用YourKit分析器来分析堆。在类加载器选项卡中有loaads sun.reflect.DelegatingClassLoader 每行有1个类的行。什么可能导致记忆不断增长?任何帮助将非常感激。

提前致谢, 卢卡斯


12167
2018-02-21 12:40


起源

MaxPermGen增加之前的价值是什么? - Shervin Asgari
Jvm使用了默认值84mb。 - Lukasz


答案:


在Sun JVM上,最初通过将JNI调用到JVM实现中来执行对属性和方法的反射访问。如果JVM注意到反射大量访问方法或字段,它将生成字节码以执行相同的操作 - 它称之为“通胀”的机制。这有一个初始速度命中,但在此之后运行速度快20倍。如果你做了很多反思,那将是一场大胜利。

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


4
2018-01-09 13:54





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

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


4
2018-02-21 15:31



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


我建议使用 Eclipse MAT 并遵循 本教程致力于permgen问题

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


3
2018-02-21 13:59



我也尝试了MAT,但这与YourKit显示的基本相同 - 很多sun.reflect.DelegatingClassLoader条目 - Lukasz


首先,对你进行如此全面的调查工作以及更好地编写你的问题的工作表示赞赏。世界(和这个网站)将是一个更好的地方,如果每个人都像你一样有才华和作家。

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

这就是为什么我像瘟疫一样避免使用JSF的原因之一。

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


1
2018-02-21 12:49



谢谢,但是现在我们甚至考虑更改Web框架。 - Lukasz
错觉。在JSF出现之前存在perm gen问题。 struts / tiles 1.x系列有一个permgen泄漏。其他框架也是如此。关于不同原因有各种各样的文章。他们都指出的一个主要观点是孤立的对象/类,由于与其他类加载器工件的链接而无法进行GBed。因此,你得到一个鸡和蛋的问题,防止类/对象被GC和内存泄漏。谷歌各种文章,看看你的代码或任何第三方代码是否“有罪”。 TIA - him
不是错误的印象。当然,没有JSF就可能发生烫发问题。我碰巧观察到一个特别糟糕的JSF实现,它可以用日to计算页面刷新时间。我建议像瘟疫一样避免它。我喜欢那些不熟悉SO的人决定花时间在1.5岁的问题上做出这样的无聊评论。 - duffymo


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


0
2018-02-21 13:35



Out应用程序不使用它们,也许某些第三方会这样做 - 要偷看,谢谢。 - Lukasz