Glassfish/Hibernate的PermGen空间问题

6
我正在Glassfish 3.1上运行一个GWT+Hibernate应用程序。几个小时后,我就会耗尽Permgen空间,即使没有任何webapp重新加载。我使用–XX:MaxPermSize=256m –XmX1024m运行。
我采纳了来自这个页面的建议,并发现我正在泄漏大量类-我的所有Hibernate模型和所有GWT RequestFactory代理。
上述指南说:“检查链条,找到意外引用并修复代码”。说起来容易做起来难。
类加载器始终指向org.glassfish.web.loader.WebappClassLoader的实例。进一步挖掘,我发现有很多来自$Proxy135和类似命名的对象的引用。但我不知道该如何继续跟进。

3
请尝试使用以下参数:-XX:+UseConcMarkSweepGC -XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m。这些参数可以改善垃圾回收的性能。 - Harry Joy
4个回答

22

新的类对象被放置在PermGen中,因此占用了越来越多的空间。无论您将PermGen空间设置得多大,它最终都会在足够的部署后达到顶峰。您需要做的是采取措施清除PermGen,以使其大小稳定。有两个JVM标志可以处理此清理:

-XX:+CMSPermGenSweepingEnabled

这个设置会在垃圾回收运行时包括PermGen空间。默认情况下,PermGen空间永远不会被包括在垃圾回收中(因此会无限增长)。

-XX:+CMSClassUnloadingEnabled

这个设置告诉PermGen垃圾回收器在类对象上采取行动。默认情况下,即使在垃圾收集期间访问PermGen空间,类对象也会得到豁免。


但我发现这种情况仅在单次部署后发生。为什么我的所有Hibernate/GWT代理仍然被应用服务器引用? - George Armhold
1
嗨,我还有一个问题,这些命令应该添加在哪里? - Minutis
在Glassfish 3中,编辑glassfish/domain_folder/config/domain.xml文件,在标签java-config中应该已经有类似的配置,只需添加新的jvm-options元素即可。 - Jacopofar

4

有一些不错的工具可以帮助处理这个问题,但你可能并不知道。JDK(1.6 u1及以上版本)附带了 jhat 和 jmap 工具。这些工具将会有很大的帮助,特别是如果你使用 jhat 的 JavaScript 查询支持。

请参考:

http://blog.ringerc.id.au/2011/06/java-ee-application-servers-learning.html

http://blogs.oracle.com/fkieviet/entry/classloader_leaks_the_dreaded_java

http://www.mhaller.de/archives/140-Memory-leaks-et-alii.html

http://blogs.oracle.com/sundararajan/entry/jhat_s_javascript_interface


4
我通过转移到Tomcat来“解决”了这个问题。

2

看起来你的类加载器存在泄漏问题。这些问题很难追踪,将以下选项添加到你实例配置的JVM选项中。

-XX:+PrintGCDetails
-XX:+TraceClassUnloading
-XX:+TraceClassLoading

现在当你运行你的应用程序时,你可以查看位于你的domain/logs文件夹中的jvm.log文件,了解正在加载和卸载的内容。很可能会发现同一个类一遍又一遍地被加载。
一个常见问题是JAXB,特别是如果你一遍又一遍地创建新的JAXBContext。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接