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

java.lang.OutOfMemoryError:永久生成空间

它是一个典型的Hibernate/JPA + IceFaces/JSF应用程序,运行在Tomcat 6和JDK 1.6上。 显然,这可能发生在重新部署应用程序几次之后。

是什么原因导致的,如何避免呢? 我该如何解决这个问题?


当前回答

或者,你可以切换到JRockit,它处理permgen的方式不同于sun的jvm。它通常也有更好的性能。

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

其他回答

如果有人在netbeans中遇到同样的错误,那么下面是我解决它的方法。

在Netbeans:

进入服务选项卡——>在服务器右侧——>选择属性——>进入平台选项卡——>在虚拟机内部选项类型-Xms1024m

在我的情况下,我给了-Xms4096m

以下是截图:

增加Tomcat内存

C:\Program Files\Apache软件基础\Tomcat 9.0\bin

或者任何使用tomcat的地方。并运行tomcat9w或任何您使用的版本。

然后跟着图片走

改变128到1024,也最大改变到1024或更多你想要的。

内存的配置取决于应用程序的性质。

你在做什么?

处理的交易数量是多少?

加载了多少数据?

etc.

etc.

etc

也许你可以配置你的应用程序,并开始清理一些模块从你的应用程序。

显然,这可能发生在重新部署应用程序几次之后

Tomcat采用热部署,但占用内存。试着每隔一段时间重新启动容器。此外,您还需要知道在生产模式下运行所需的内存量,这似乎是进行研究的好时机。

我也有类似的问题。 我的是基于JDK 7 + Maven 3.0.2 + Struts 2.0 +谷歌GUICE依赖注入的项目。

当我尝试运行mvn清洁包命令时,它显示以下错误和“BUILD FAILURE”发生

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException;java.lang.reflect.InvocationTargetException: null java.lang.reflect.InvocationTargetException 由:java.lang.OutOfMemoryError: PermGen space引起

我尝试了上面所有有用的技巧,但不幸的是,没有一个对我有效。 对我有效的方法如下:=>

转到pom.xml 搜索<artifactId>maven-surefire-plugin</artifactId> 添加一个新的<configuration>元素和<argLine>子元素,其中pass -Xmx512m -XX:MaxPermSize=256m,如下所示=>

< configuration > < argLine > -Xmx512m -XX: MaxPermSize = 256m < / argLine > < / configuration >

希望能有所帮助,编程愉快:)

在部署和取消部署一个复杂的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();