最近,我在我的web应用程序中遇到了这个错误:
java.lang.OutOfMemoryError:永久生成空间
它是一个典型的Hibernate/JPA + IceFaces/JSF应用程序,运行在Tomcat 6和JDK 1.6上。 显然,这可能发生在重新部署应用程序几次之后。
是什么原因导致的,如何避免呢? 我该如何解决这个问题?
最近,我在我的web应用程序中遇到了这个错误:
java.lang.OutOfMemoryError:永久生成空间
它是一个典型的Hibernate/JPA + IceFaces/JSF应用程序,运行在Tomcat 6和JDK 1.6上。 显然,这可能发生在重新部署应用程序几次之后。
是什么原因导致的,如何避免呢? 我该如何解决这个问题?
当前回答
outofmemoryerror: PermGen space消息表示内存中的永久生成区域已耗尽。
任何Java应用程序都允许使用有限的内存。特定应用程序可以使用的确切内存量是在应用程序启动时指定的。
Java内存被划分为不同的区域,如下图所示:
Metaspace:一个新的内存空间诞生
JDK 8 HotSpot JVM现在使用本机内存来表示类元数据,被称为Metaspace;类似于Oracle的JRockit和IBM的JVM。
好消息是,这意味着不再存在java.lang.OutOfMemoryError: PermGen空间问题,也不再需要使用Java_8_Download或更高版本来调优和监视这个内存空间。
其他回答
我也有类似的问题。 我的是基于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 >
希望能有所帮助,编程愉快:)
outofmemoryerror: PermGen space消息表示内存中的永久生成区域已耗尽。
任何Java应用程序都允许使用有限的内存。特定应用程序可以使用的确切内存量是在应用程序启动时指定的。
Java内存被划分为不同的区域,如下图所示:
Metaspace:一个新的内存空间诞生
JDK 8 HotSpot JVM现在使用本机内存来表示类元数据,被称为Metaspace;类似于Oracle的JRockit和IBM的JVM。
好消息是,这意味着不再存在java.lang.OutOfMemoryError: PermGen空间问题,也不再需要使用Java_8_Download或更高版本来调优和监视这个内存空间。
增加Tomcat内存
C:\Program Files\Apache软件基础\Tomcat 9.0\bin
或者任何使用tomcat的地方。并运行tomcat9w或任何您使用的版本。
然后跟着图片走
改变128到1024,也最大改变到1024或更多你想要的。
他们说Tomcat的最新版本(6.0.28或6.0.29)可以更好地处理重新部署servlet的任务。
在部署和取消部署一个复杂的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();