当前位置:  开发笔记 > 编程语言 > 正文

处理"java.lang.OutOfMemoryError:PermGen space"错误

如何解决《处理"java.lang.OutOfMemoryError:PermGenspace"错误》经验,为你挑选了17个好方法。

最近我在我的Web应用程序中遇到了这个错误:

java.lang.OutOfMemoryError:PermGen空间

这是在Tomcat 6和JDK 1.6上运行的典型Hibernate/JPA + IceFaces/JSF应用程序.显然,重新部署应用程序几次后就会发生这种情况.

导致它的原因以及可以采取哪些措施来避免它?我该如何解决这个问题?



1> Chris..:

解决方案是在启动Tomcat时将这些标志添加到JVM命令行:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

您可以通过关闭tomcat服务,然后进入Tomcat/bin目录并运行tomcat6w.exe来实现.在"Java"选项卡下,将参数添加到"Java选项"框中.单击"确定",然后重新启动该服务.

如果您收到错误,则指定的服务不作为已安装的服务存在,您应该运行:

tomcat6w //ES//servicename

其中servicename是services.msc中查看的服务器名称

资料来源:orx对Eric的Agile Answers的评论.


首先,解释这些标志真正做的事情会很棒.只是说:"做那个,享受"是不够的恕我直言.
下面的文章建议-XX:+ UseConcMarkSweepGC和-XX:MaxPermSize = 128m.http://my.opera.com/karmazilla/blog/2007/03/13/good-riddance-permgen-outofmemoryerror
-XX:+ CMSPermGenSweepingEnabled此选项会降低性能.这使得每个请求在我们的系统上花费的时间比平常多三倍.小心使用.
在tomcat 6.0.29启动时,从我的catalina.out日志文件:"请在将来使用CMSClassUnloadingEnabled代替CMSPermGenSweepingEnabled"
为我工作 - 谢谢 - 我在使用Tomcat6的Ubuntu 10.10上这样做 - 我创建了一个新文件:/usr/share/tomcat6/bin/setenv.sh并添加了以下行:JAVA_OPTS =" - Xms256m -Xmx512m - XX:+ CMSClassUnloadingEnabled -XX:+ CMSPermGenSweepingEnabled" - 使用以下命令重启tomcat:sudo /etc/init.d/tomcat6 start
-XX:+ CMSClassUnloadingEnabled和-XX:+ CMSPermGenSweepingEnabled在Java 1.7不可用,见[链接](http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html#BehavioralOptions)
第二,如果你的应用程序确实泄漏了类加载器,这意味着即使在取消部署之后,它仍会留下应用程序的类加载器加载的某个对象或类,那么这些标志将无济于事.我在这个主题上写过博客文章和其他建议:http://plumbr.eu/blog/busting-permgen-myths
要了解有关旗帜的更多信息 - http://stackoverflow.com/questions/3334911/what-does-jvm-flag-cmsclassunloadingenabled-actually-do

2> 小智..:

你最好尝试-XX:MaxPermSize=128M而不是-XX:MaxPermGen=128M.

我无法准确地使用这个内存池,但它与加载到JVM中的类的数量有关.(因此为tomcat启用类卸载可以解决问题.)如果应用程序在运行时生成并编译类,则更可能需要大于默认值的内存池.


实际上,这只会推迟OOMError.请参阅下面的答案,由anon发起,有两个链接到frankkieviet博客.

3> 小智..:

多个部署后发生的应用程序服务器PermGen错误很可能是由容器保存到旧应用程序的类加载器中的引用引起的.例如,使用自定义日志级别类将导致应用程序服务器的类加载器保留引用.您可以使用现代(JDK6 +)JVM分析工具(如jmap和jhat)来查看这些类间加载器泄漏,以查看应用程序中继续保留哪些类,以及重新设计或消除它们的使用.通常的嫌疑人是数据库,记录器和其他基础框架级库.

请参阅Classloader泄漏:可怕的"java.lang.OutOfMemoryError:PermGen space"异常,特别是其后续帖子.


虽然这在理论上可以回答这个问题,[但最好](http://meta.stackexchange.com/q/8259)在这里包含答案的基本部分,并提供参考链接.
这只是问题的真正解决方案,在某些情况下难以实施.

4> 小智..:

人们常犯的错误是认为堆空间和permgen空间是相同的,这根本不是真的.您可能在堆中剩余大量空间但仍可能在permgen中耗尽内存.

PermGen中OutofMemory的常见原因是ClassLoader.每当将类加载到JVM中时,其所有元数据以及类加载器都保存在PermGen区域,并且当加载它们的类加载器准备好进行垃圾回收时,它们将被垃圾收集.在案例类中,类加载器有一个内存泄漏,它所加载的所有类都将保留在内存中,并且一旦重复几次就会导致permGen outofmemory.经典的例子是Java.lang.OutOfMemoryError:Tomcat中的PermGen空间.

现在有两种方法可以解决这个问题:
1.找出内存泄漏的原因或是否有任何内存泄漏.
2.使用JVM参数-XX:MaxPermSize和增加PermGen Space的大小-XX:PermSize.

您还可以在Java中查看2解决Java.lang.OutOfMemoryError的更多详细信息.


如何传递参数`-XX:MaxPermSize和-XX:PermSize` ?? 我找不到`catalina.bat`.我的tomcat版本是`5.5.26`.

5> 小智..:

-XX:MaxPermSize=128m对Sun JVM 使用命令行参数(显然将128替换为您需要的任何大小).


@TimHowland,如果根本原因不是类加载器泄漏,那么它可以是永久修复,只是Web应用程序中的类/静态数据太多.
唯一的问题是你只是推迟了不可避免的事情 - 在某些时候你也会在那里耗尽余量.这是一个非常实用的解决方案,但它并没有永久解决它.

6> 小智..:

尝试-XX:MaxPermSize=256m,如果它仍然存在,请尝试-XX:MaxPermSize=512m


如果它仍然存在,请尝试`XX:MaxPermSize = 1024m` :)
如果它仍然存在,请尝试XX:MaxPermSize = 2048m :)
你也可以尝试8192米,但这有点矫枉过正
如果仍然存在,请重新考虑您的申请!或者尝试XX:MaxPermSize = 4096m :)
确实有点过分 - 640KB对任何人都应该足够了!
让我们看看... 2012年人们说1024,2013年是2048年,2014年是4096年,2015年到达8192.现在只需花费100美元购买16384.

7> prayagupd..:

我添加 -XX: MaxPermSize = 128m(你可以尝试哪种方法效果最好)到VM Arguments,因为我正在使用eclipse ide.在大多数JVM中,默认的PermSize大约为64MB,如果项目中有太多的类或大量的字符串,则会耗尽内存.

对于日食,它也在答案中描述.

步骤1:双击服务器选项卡上的tomcat服务器

在此输入图像描述

第2 :打开启动Conf并添加-XX: MaxPermSize = 128m到现有VM争论的末尾.

在此输入图像描述



8> 小智..:

在部署和取消部署复杂的Web应用程序时,我一直在反对这个问题,并且认为我会添加一个解释和我的解决方案.

当我在Apache Tomcat上部署应用程序时,会为该应用程序创建一个新的ClassLoader.然后使用ClassLoader加载所有应用程序的类,并且在取消部署时,一切都应该很好地消失.然而,实际上它并不那么简单.

在Web应用程序生命周期中创建的一个或多个类包含一个静态引用,该引用位于该行的某个位置,引用ClassLoader.由于引用最初是静态的,因此没有任何垃圾收集会清除此引用 - ClassLoader及其加载的所有类都将保留.

经过几次重新部署后,我们遇到了OutOfMemoryError.

现在这已成为一个相当严重的问题.我可以确保在每次重新部署后重新启动Tomcat,但这会占用整个服务器,而不仅仅是重新部署的应用程序,这通常是不可行的.

因此,我在代码中整理了一个解决方案,该解决方案适用于Apache Tomcat 6.0.我没有在任何其他应用程序服务器上进行测试,并且必须强调,如果不对任何其他应用程序服务器进行修改,这很可能无法工作.

我还想说,我个人讨厌这段代码,如果现有代码可以更改为使用正确的关闭和清理方法,那么没有人应该将其用作"快速修复".唯一应该使用的是如果有一个外部库,你的代码依赖于它(在我的情况下,它是一个RADIUS客户端),它不提供清理自己的静态引用的方法.

无论如何,关于代码.这应该在应用程序取消部署时调用 - 例如servlet的destroy方法或(更好的方法)ServletContextListener的contextDestroyed方法.

//Get a list of all classes loaded by the current webapp classloader
WebappClassLoader classLoader = (WebappClassLoader) getClass().getClassLoader();
Field classLoaderClassesField = null;
Class clazz = WebappClassLoader.class;
while (classLoaderClassesField == null && clazz != null) {
    try {
        classLoaderClassesField = clazz.getDeclaredField("classes");
    } catch (Exception exception) {
        //do nothing
    }
    clazz = clazz.getSuperclass();
}
classLoaderClassesField.setAccessible(true);

List classes = new ArrayList((Vector)classLoaderClassesField.get(classLoader));

for (Object o : classes) {
    Class c = (Class)o;
    //Make sure you identify only the packages that are holding references to the classloader.
    //Allowing this code to clear all static references will result in all sorts
    //of horrible things (like java segfaulting).
    if (c.getName().startsWith("com.whatever")) {
        //Kill any static references within all these classes.
        for (Field f : c.getDeclaredFields()) {
            if (Modifier.isStatic(f.getModifiers())
                    && !Modifier.isFinal(f.getModifiers())
                    && !f.getType().isPrimitive()) {
                try {
                    f.setAccessible(true);
                    f.set(null, null);
                } catch (Exception exception) {
                    //Log the exception
                }
            }
        }
    }
}

classes.clear();



9> Santosh Jadi..:

java.lang.OutOfMemoryError: PermGen空间信息表明持久代的内存区域被耗尽.

允许任何Java应用程序使用有限的内存.在应用程序启动期间指定特定应用程序可以使用的确切内存量.

Java内存分为不同的区域,可以在下图中看到:

在此输入图像描述

Metaspace:一个新的记忆空间诞生了

JDK 8 HotSpot JVM现在使用本机内存来表示类元数据,称为Metaspace; 类似于Oracle JRockit和IBM JVM.

好消息是它意味着没有更多的java.lang.OutOfMemoryError: PermGen空间问题,您无需使用Java_8_Download或更高版本来调整和监视此内存空间.



10> Jeremy..:

或者,您可以切换到JRockit,其处理permgen与sun的jvm不同.它通常也有更好的性能.

http://www.oracle.com/technetwork/middleware/jrockit/overview/index.html


虽然JRockit确实没有PermGen,但从长远来看这无济于事.你会得到`java.lang.OutOfMemoryError:没有足够的本机内存`.

11> faisalbhagat..:

1)增加PermGen内存大小

人们可以做的第一件事就是使永久代堆空间的大小更大.使用通常的-Xms(设置初始堆大小)和-Xmx(设置最大堆大小)JVM参数无法做到这一点,因为如上所述,永久生成堆空间完全独立于常规Java堆空间,并且这些参数设置此常规Java堆空间的空间.但是,有一些类似的参数可以使用(至少使用Sun/OpenJDK jvms)来使永久代堆的大小更大:

 -XX:MaxPermSize=128m

默认值为64米.

2)启用扫描

另一种妥善处理的方法是允许卸载类,这样你的PermGen就永远不会用完:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

这样的东西在过去对我有用.但有一件事,在使用这些产品时会有显着的性能折衷,因为permgen扫描会对您提出的每个请求或类似的内容提出额外的2个请求.您需要平衡使用与权衡.

您可以找到此错误的详细信息.

http://faisalbhagat.blogspot.com/2014/09/java-outofmemoryerror-permgen.html



12> 小智..:

我遇到了我们在这里讨论的问题,我的场景是eclipse-helios + tomcat + jsf,你正在做的是将一个简单的应用程序部署到tomcat.我在这里展示了同样的问题,解决方法如下.

在eclipse中转到服务器选项卡双击我的案例tomcat 7.0中的注册服务器,它打开我的文件服务器常规注册信息.在"常规信息"部分单击"打开启动配置"链接,这将在"参数"选项卡中打开服务器选项的执行,最后添加这两个条目的VM参数

-XX: MaxPermSize = 512m
-XX: PermSize = 512m

准备好了.



13> Edwin Buck..:

这些天最简单的答案是使用Java 8.

它不再为PermGen空间专门保留内存,允许PermGen内存与常规内存池混合使用.

请记住,-XXPermGen...=...如果您不希望Java 8抱怨它们不执行任何操作,则必须删除所有非标准JVM启动参数.


@bluish感谢您指出这一点; 然而,在谈论OutOfMemoryExceptions和泄漏元数据时,这个答案全面横行.它也没有提到删除PermGen选项的重要方面.简而言之,我不确定我会改进答案,而是重写它.如果它只是一个快速的修饰,我会觉得不那么犹豫,但看起来它不仅仅是一个快速的修饰,我不想冒犯原作者.尽管如此,这个答案清单是狗的混乱的晚餐,也许杀死我的帖子无论如何都是最好的.

14> Lucky..:

    从Tomcat的bin目录中打开tomcat7w或在开始菜单中键入Monitor Tomcat(将打开一个带有各种服务信息的选项卡式窗口).

    在Java Options文本区域中添加以下行:

    -XX:MaxPermSize=128m
    

    将Initial Memory Pool设置为1024(可选).

    将Maximum Memory Pool设置为1024(可选).

    单击确定.

    重新启动Tomcat服务.



15> 小智..:

由于使用大空间而不是jvm提供空间来执行代码,因此发生了perm gen space错误.在UNIX操作系统中解决此问题的最佳解决方案是更改bash文件上的某些配置.以下步骤解决问题.

gedit .bashrc在终端上运行命令.

JAVA_OTPS使用以下值创建变量:

export JAVA_OPTS="-XX:PermSize=256m -XX:MaxPermSize=512m"

保存bash文件.在终端上运行命令exec bash.重启服务器.

我希望这种方法能解决你的问题.如果使用的Java版本低于8,则有时会出现此问题.但是,如果您使用Java 8,问题永远不会发生.



16> Yannis Serme..:

此外,如果您在webapp中使用log4j,请在log4j 文档中查看此段落.

似乎如果您正在使用PropertyConfigurator.configureAndWatch("log4j.properties"),则在取消部署Web应用程序时会导致内存泄漏.



17> Nikem..:

如果您有真正的内存泄漏,增加永久生成大小或调整GC参数将无济于事.如果您的应用程序或它使用的某个第三方库,泄漏类加载器,唯一真正和永久的解决方案是找到此泄漏并修复它.有许多工具可以帮助您,最近的一个是Plumbr,它刚刚发布了具有所需功能的新版本.

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有