JBoss 7,java.lang.OutOfMemoryError:PermGen空间

时间:2012-07-25 09:17:37

标签: java-ee jboss webserver jboss7.x

我遇到了这个错误,其中CPU使用率达到极限,JBoss需要重新启动(java.lang.OutOfMemoryError: PermGen space)。

我找到了旧版JBoss版本的解决方案来增加MaxPermSize。我想JBoss7也是如此。

为了不再遇到任何问题,哪个值足够好?有没有办法永久地摆脱这个问题(比如让我们说像JRockit一样使用不同的虚拟机)?

4 个答案:

答案 0 :(得分:55)

由于在多次重新展开后发生这种情况,听起来好像您遇到了classloader leak,这是一种常见的permgen leak

这些可爱的野兽是由于从容器拥有的对象到从应用程序类加载器加载的类的实例的对象的正常(非弱)引用而发生的。如果在取消部署时没有清除这些引用,那么应用程序的类加载器仍然存在强大的引用链,因此无法进行GC并且无法释放已加载的类。

一个常见原因是容器类中的静态集合,它们添加了对应用程序类的非静态引用。

JBoss AS 7在其模块系统中有一些相当强大的规定来防止类加载器泄漏,所以我很惊讶你已经设法触发了一个。自从我从Glassfish搬到AS7后,我没有看到类加载器泄漏。

增加MaxPermSize会给你带来一些时间,但它不会解决问题。

你真的需要解决为什么类加载器泄漏。这样做很有趣。您享受税收,间歇性故障和清洁淋浴,对吗?查看一些博客的第一个标题中的链接,这些链接将帮助您开始跟踪泄漏情况。基本上,您需要使用VisualVMOQL来挖掘对应用程序类加载器的引用,或者进行堆转储并使用jhat(JDK的一部分)来查找引用。无论哪种方式,我们的想法是通过应用类的实例确定从应用服务器到类加载器的强引用链的位置。

或者,它可以帮助您获取应用程序的副本然后开始从其中删除位,直到泄漏消失。您可以通过将VisualVM或其他监视连接到应用服务器VM并观察PermGen在两个或更多部署/取消部署周期后是否增加来判断它是否泄漏。考虑自动化部署/取消部署周期。将泄漏的原因缩小到应用程序的一小部分和/或其中一个依赖项,并生成一个小的,独立的测试用例,然后将其作为错误报告提交给(a)JBoss AS 7,因为它是AFAIK它的意图阻止这种情况发生,以及(b)持有参考的罪魁祸首。

如果将原因缩小到部署存档中捆绑的依赖关系,将其移动到JBoss AS 7模块可能会解决问题。为它创建一个JBoss模块,将其部署到AS7的modules目录,并通过Manifest.MFjboss-deployment-structure.xml向部署添加依赖项。请参阅documentation on the AS7 class loader

这就是为什么Project Jigsaw被推迟的事实让我感到难过。 Java 需要一个强大的模块系统,可以摆脱这种混乱。

答案 1 :(得分:8)

VM参数为:

-XX:MaxPermSize=256M

只要使它足够大,你就不会达到极限。

从广义上讲,perm gen memory用于与Classes和interned Strings相关联的对象。除非你使用了很多不同的类,否则你不应该用完。

答案 2 :(得分:4)

我们必须做同样的事情,不幸的是,visualvm并没有为我们做太多。

我们最终使用eclipse mat分析崩溃时生成的堆转储,然后查看了leak suspects报告,该报告告诉我们有很多ModuleClassLoader个实例被泄露。

点击概览标签中的其中一个实例,然后选择merge shortest paths to GC roots + exclude weak references,这给了我们一个不允许这些ModuleClassLoader个实例进行GC修改的罪魁祸首!

https://smalldata.tech/blog/2015/09/29/detecting-java-permgen-memory-leak

答案 3 :(得分:1)

为什么会这样?

  

" PermGen"当Java虚拟机耗尽时,会发生错误   永久世代的记忆。回想一下,Java有一个   世代垃圾收集器,四代:伊甸园,年轻,   古老而永久。在伊甸园中,物体很短   生活和垃圾收集很快,经常。年轻一代   由伊甸园生成(或被推动)幸存的物体组成   因为当时伊甸园的一代人已经满了,所以一直到年轻   分配),年轻一代的垃圾收集较少   频繁但仍然以相当规律的间隔发生(前提是这样)   你的应用程序实际上做了一些事情,并分配对象   时不时)。老一代,好吧,你想通了。它包含   在年轻一代幸存下来或被推倒的物体,   垃圾收集更少见,但仍然可以发生。   最后,永久的一代。这是针对的对象   虚拟机决定支持永生 - 这就是   恰恰是问题的核心。永久世代中的物体   永远不会被垃圾收集;也就是说,在正常情况下   jvm以正常的命令行参数启动。所以呢   重新部署Web应用程序时发生的是您的WAR文件   解压缩并将其类文件加载到jvm中。而且这里是   事情:几乎总是在永久世代中结束......(采取   从:   http://rlogiacco.blogspot.com/2009/02/jboss-and-permgen-outofmemoryerror.html

以下是一些建议:

将此参数用于JVM。他们告诉垃圾收集器也在PermGen上调用它的算法。

set JAVA_OPTS=-Xms512m -Xmx1024m 
-XX:PermSize=512m 
-XX:MaxPermSize=1024m 
-XX:+UseConcMarkSweepGC 
-XX:+CMSPermGenSweepingEnabled 
-XX:+CMSClassUnloadingEnabled 
  • CMSPermGenSweepingEnabled 设置包含一个PermGen 垃圾收集运行。默认情况下,PermGen空间永远不会 包含在垃圾收集中(因此无限制地增长)。
  • CMSClassUnloadingEnabled 设置告诉PermGen垃圾 集合扫描对类对象采取操作。默认情况下,类 即使在PermGen空间存在时,对象也会获得豁免 在一次收集期间访问过。

重新启动JBOSS,因为每次部署应用程序时,都会增加PermGen中的数据量。

您也可以使用JRocket JVM代替Sun JVM。它的垃圾收集器算法中没有任何PermGen。