我遇到了一个错误,导致 CPU 使用率达到极限并且 JBoss 需要重新启动 (java.lang.OutOfMemoryError: PermGen space
)。
我找到了一个解决方案,适用于旧版本的 JBoss,可以增加 MaxPermSize
的值。我想对于 JBoss7 也是同样的情况。
哪个值足够好,以便不再遇到此问题?是否有任何方法永久地解决这个问题(比如说使用一个不同的虚拟机,如 JRockit)?
我遇到了一个错误,导致 CPU 使用率达到极限并且 JBoss 需要重新启动 (java.lang.OutOfMemoryError: PermGen space
)。
我找到了一个解决方案,适用于旧版本的 JBoss,可以增加 MaxPermSize
的值。我想对于 JBoss7 也是同样的情况。
哪个值足够好,以便不再遇到此问题?是否有任何方法永久地解决这个问题(比如说使用一个不同的虚拟机,如 JRockit)?
由于多次重新部署后出现这种情况,看起来你遇到了一种类加载器泄漏,这是一种常见的永久代内存泄漏。
这些可爱的生物发生在容器中拥有对象的正常(非弱)引用指向从应用程序类加载器加载的类的实例的对象。如果这些引用在取消部署时没有清除,则仍存在一个对应用程序类加载器的强引用链,因此无法进行GC,也不能释放已加载的类。
常见的原因是容器类中的静态集合具有对应用程序类添加的非静态引用。
JBoss AS 7在其模块系统中有一些相当强的规定,可以防止类加载器泄漏,因此我很惊讶您已经成功触发了一个。自从我从Glassfish转移到AS7以来,我就没有看到过类加载器泄漏。
增加MaxPermSize会为您赢得一些时间,但它不会解决问题。
你真的需要弄清楚为什么类加载器会泄漏。这很“有趣”。你喜欢交税,间歇性故障和清洁淋浴吧?请参见第一段中的链接以了解一些博客,从而开始跟踪泄漏。基本上,您将想使用VisualVM和OQL来挖掘对您的应用程序类加载器的引用,或者获取堆转储并使用jhat
(JDK的一部分)查找引用。无论哪种方式,目标都是找出从应用服务器到您的类加载器的强引用链,通过您的应用程序类的实例。
另外,可以通过复制你的应用程序然后逐步删除其中一些部分来帮助解决内存泄漏。通过连接VisualVM或其他监控到应用服务器VM,观察在两个或更多的部署/卸载周期后PermGen是否增加来判断是否存在泄漏问题。考虑自动化部署/卸载周期。将泄漏原因缩小到你的应用程序中的一小部分或一个依赖项,并生成一个小型的、自包含的测试用例,然后将其作为错误报告提交到(a)JBoss AS 7上,因为据我所知,它应该会阻止这种情况发生,以及(b)持有引用的罪魁祸首。
如果你将问题缩小到被捆绑在你的部署归档文件中的某个依赖项上,将其移动到JBoss AS 7模块可能会解决问题。为其创建一个JBoss模块,将其部署到AS7的modules
目录中,并通过Manifest.MF
或jboss-deployment-structure.xml
向你的部署添加对其的依赖性。请参阅有关AS7类加载器的文档。
这就是为什么推迟项目Jigsaw让我感到难过的原因。Java需要一个强大的模块系统来清除这种冗余。
虚拟机参数是:
-XX:MaxPermSize=256M
只要将它设定得足够大,您就不会达到限制。
一般来说,永久代内存用于与类和国际化字符串相关联的对象。除非使用了很多不同的类,否则您不应该用尽它。
https://smalldata.tech/blog/2015/09/29/detecting-java-permgen-memory-leak
set JAVA_OPTS=-Xms512m -Xmx1024m
-XX:PermSize=512m
-XX:MaxPermSize=1024m
-XX:+UseConcMarkSweepGC
-XX:+CMSPermGenSweepingEnabled
-XX:+CMSClassUnloadingEnabled
每次部署应用程序都会增加PermGen中的数据量,因此请重新启动JBOSS。
您还可以使用JRocket JVM而不是Sun JVM。它在其Garbage Collector算法中没有任何PermGen。