处理“java.lang.OutOfMemoryError: PermGen space”错误

Dealing with "java.lang.OutOfMemoryError: PermGen space" error

提问人: 提问时间:9/18/2008 最后编辑:8 revs, 6 users 55%Chris 更新时间:3/14/2022 访问量:1062602

问:

最近,我在Web应用程序中遇到了以下错误:

java.lang.OutOfMemoryError:PermGen 空间

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

是什么原因导致的,可以做些什么来避免它? 如何解决该问题?

异常 memory-leaks out-of-memory java-6 permgen jrockit

评论

0赞 masT 11/14/2013
我在添加显示 taglib 时遇到此错误。删除 so 也解决了错误。为什么会这样?
0赞 Thorbjørn Ravn Andersen 2/25/2014
你是怎么碰到的?
15赞 Rytek 3/21/2014
使用 JDK 1.8 :þ 欢迎来到元空间
0赞 Eran Medan 1/14/2010
我已经为此奋斗了几个小时,但我没有好消息。请参阅我的相关问题:stackoverflow.com/questions/1996088/...您可能仍然有内存泄漏,例如,类未进行垃圾回收,因为 WebAppClassLoader 未进行垃圾回收(它具有未清除的外部引用)。增加 PermGen 只会延迟 OutOfMemoryError,并且允许类垃圾回收是一个前提条件,但如果类加载器仍然引用类,则不会对类进行垃圾回收。
0赞 JustBeingHelpful 2/25/2017
如果使用 Windows,请按照以下说明操作,而不是尝试在配置文件中手动设置标志。这将正确地设置注册表中的值,以便在运行时由 Tomcat 调用。stackoverflow.com/questions/21104340/......

答:

572赞 4 revs, 4 users 60%Chris #1

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

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

tomcat6w //ES//servicename

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

来源:orx 对 Eric 的 Agile Answers 的评论。

评论

39赞 Taylor Leese 5/28/2009
下面的文章也建议使用 -XX:+UseConcMarkSweepGC 和 -XX:MaxPermSize=128m。my.opera.com/karmazilla/blog/2007/03/13/......
31赞 Eldelshell 9/3/2010
-XX:+CMSPermGenSweepingEnabled 此选项会降低性能。这使得每个请求花费的时间比我们系统上的平时多三倍。请小心使用。
10赞 sami 12/10/2010
为我工作 - 谢谢 - 我正在使用 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
24赞 knb 7/27/2011
在 tomcat 6.0.29 启动时,从我的 catalina.out 日志文件中:“将来请使用 CMSClassUnloadingEnabled 代替 CMSPermGenSweepingEnabled”
225赞 Nikem 7/23/2012
首先,解释一下这些标志的真正作用会很棒。恕我直言,仅仅说:“这样做并享受”是不够的。
17赞 Jeremy 9/18/2008 #2

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

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

评论

4赞 stracktracer 7/27/2012
虽然 JRockit 确实没有 PermGen,但从长远来看,这无济于事。你会得到相反的。java.lang.OutOfMemoryError: There is insufficient native memory
4赞 Tim Howland 9/18/2008 #3

也为我解决了这个问题;但是,我注意到 servlet 重启时间要差得多,所以虽然它在生产中更好,但在开发中有点拖累。

43赞 user17163 9/18/2008 #4

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

评论

9赞 Tim Howland 9/18/2008
唯一的问题是你只是在拖延不可避免的事情——在某个时候,你也会用完那里的空间。这是一个很好的务实解决方案,但它并不能永久解决它。
0赞 Matt 9/23/2008
同样的事情发生在 Eclipse 中,任何时候你都有大量的动态类加载。类加载者不会被处理掉,而是永远生活在永恒的一代中
1赞 Dave 10/31/2011
我在执行一个特别大的 Hudson 作业时用完了 PermGen......这为我修复了它。
10赞 Péter Török 12/14/2011
@TimHowland,如果根本原因不是类加载器泄漏,而只是 Web 应用程序中的类/静态数据过多,这可能是一个永久性修复。
0赞 louisgab 2/27/2014
从源代码构建 jenkins/hudson 时遇到了与 HDave 相同的问题。
154赞 5 revs, 4 users 43%anon #5

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

参见 Classloader leaks: the dreaded “java.lang.OutOfMemoryError: PermGen space” exception,尤其是它的后续文章

评论

3赞 Rade_303 6/8/2012
这才是解决问题的真正方法,在某些情况下太难实施了。
0赞 gavenkoa 12/23/2012
另一个非常好的来源是 people.apache.org/~markt/presentations/(来自Tomcat发布经理!!).
22赞 Joachim Sauer 4/9/2013
虽然这在理论上可以回答这个问题,但最好在这里包括答案的基本部分,并提供链接以供参考。
40赞 3 revs, 3 users 50%bassist #6

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

评论

59赞 igo 4/12/2013
如果仍然存在,请尝试:)XX:MaxPermSize=1024m
40赞 Thomas 7/31/2013
如果它仍然存在,请尝试 XX:MaxPermSize=2048m :)
18赞 Jonathan Airey 10/6/2014
如果它仍然存在,请重新考虑您的应用程序!或者试试 XX:MaxPermSize=4096m :)
19赞 Jacek Pietal 10/17/2014
你也可以试试 8192m,但这有点矫枉过正
14赞 Joel Purra 3/24/2015
确实是矫枉过正了——640KB 对任何人来说都足够了!
3赞 OscarRyz 3/12/2009 #7

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

你在干什么?

之前的交易金额是多少?

您加载了多少数据?

等。

等。

也许你可以分析你的应用,并开始清理你的应用中的一些模块。

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

Tomcat 具有热部署功能,但会消耗内存。尝试偶尔重新启动容器。此外,您还需要知道在生产模式下运行所需的内存量,这似乎是进行研究的好时机。

252赞 2 revs, 2 users 80%toesterdahl #8

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

我无法说出这个内存池的确切用途,但它与加载到 JVM 中的类数量有关。(因此,启用 tomcat 的类卸载可以解决该问题。如果应用程序在运行时生成和编译类,则更有可能需要比默认值更大的内存池。

评论

9赞 Rade_303 6/8/2012
实际上,这只会推迟 OOMError。请参阅下面由 anon 开始的答案,其中包含两个指向 frankkieviet 博客的链接。
0赞 amos 2/14/2014
这些选项解释如下:oracle.com/technetwork/java/javase/tech/...
4赞 2 revs, 2 users 67%Pankaj Shinde #9

我有一个 Hibernate+Eclipse RCP 的组合,尝试使用并且它似乎对我有用。-XX:MaxPermSize=512m-XX:PermSize=512m

4赞 2 revs, 2 users 57%sandeep #10

设置。稍后,您也可以尝试增加 .希望它能起作用。这同样适用于我。只有设置对我不起作用。-XX:PermSize=64m -XX:MaxPermSize=128mMaxPermSizeMaxPermSize

3赞 Tony Ennis #11

他们说 Tomcat 的最新版本(6.0.28 或 6.0.29)可以更好地处理重新部署 servlet 的任务。

2赞 Ross Peoples #12

“他们”是错误的,因为我正在运行 6.0.29,即使在设置了所有选项后也遇到了同样的问题。正如蒂姆·豪兰德(Tim Howland)上面所说,这些选择只会推迟不可避免的事情。它们允许我在遇到错误之前重新部署 3 次,而不是每次重新部署。

2赞 3 revs, 2 users 64%Hrishikesh Kumar #13

如果您在eclipse IDE中得到此消息,即使在设置了参数,,等之后,仍然遇到相同的错误,则很可能是eclipse使用的JRE版本有问题,该版本将由某些第三方应用程序安装并设置为默认值。这些有问题的版本不会获取 PermSize 参数,因此无论您设置什么,您仍然会不断收到这些内存错误。因此,在您的eclipse.ini中添加以下参数:--launcher.XXMaxPermSize-XX:MaxPermSize

-vm <path to the right JRE directory>/<name of javaw executable>

此外,请确保在 eclipse 的首选项中将默认 JRE 设置为正确的 java 版本。

2赞 5 revs, 5 users 35%user1985910 #14

唯一对我有用的方法是使用 JRockit JVM。我有MyEclipse 8.6。

JVM 的堆存储了正在运行的 Java 程序生成的所有对象。Java 使用运算符创建对象,并在运行时在堆上分配新对象的内存。垃圾回收是一种自动释放程序不再引用的对象所包含的内存的机制。new

14赞 4 revs, 4 users 57%Hugo Mendoza #15

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

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

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

并准备好了。

3赞 2 revsMaze #16

我遇到了完全相同的问题,但不幸的是,没有一个建议的解决方案真正适合我。这个问题在部署期间没有发生,我也没有做任何热部署。

就我而言,在执行我的 Web 应用程序期间,每次在连接(通过休眠)数据库时,问题都会发生。

这个链接(前面也提到过)确实提供了足够的内部信息来解决问题。将 jdbc-(mysql)-driver 移出 WEB-INF 并移入 jre/lib/ext/ 文件夹似乎已经解决了这个问题。这不是理想的解决方案,因为升级到较新的 JRE 需要重新安装驱动程序。 另一个可能导致类似问题的候选者是 log4j,因此您可能也希望移动该候选者

评论

0赞 Scot 5/29/2014
如果您不想在 jre/lib/ext 中包含驱动程序,则可以通过将驱动程序包含在容器启动类路径中来获得相同的结果。java -cp /path/to/jdbc-mysql-driver.jar:/path/to/container/bootstrap.jar容器。开始
5赞 2 revs, 2 users 50%sermojohn #17

此外,如果您在 Web 应用程序中使用 log4j,请查看 log4j 文档中的此段落。

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

23赞 Edward Torbett #18

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

评论

0赞 Edward Torbett 9/5/2019
我知道我写这篇文章已经 8 年多了,但从那时到现在的某个时候,我找到了更深层次的根本原因和解决方案。这是因为,虽然 Web 应用程序中的所有类都归上下文类加载器所有,但调用启动和关闭回调的线程归父类加载器所有。这意味着,如果关闭代码初始化线程局部变量,这将导致父类加载器最终保留对上下文类加载器的引用,从而阻止良好的清理。
0赞 Edward Torbett 9/5/2019
幸运的是,有一个非常简单的修复方法 - 将当前在 shutdown 方法中的所有代码移动到新 Thread 对象的 run 方法中。然后在 shutdown 方法中,启动此线程并等待它完成。清理代码将以相同的方式执行,但任何线程局部变量仍将绑定到上下文类加载器,而不是泄漏。
4赞 2 revs, 2 users 71%kiwilisk #19

我尝试了几个答案,最终唯一完成这项工作的是 pom 中编译器插件的配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
        <fork>true</fork>
        <meminitial>128m</meminitial>
        <maxmem>512m</maxmem>
        <source>1.6</source>
        <target>1.6</target>
        <!-- prevent PermGen space out of memory exception -->
        <!-- <argLine>-Xmx512m -XX:MaxPermSize=512m</argLine> -->
    </configuration>
</plugin>

希望这个有帮助。

评论

0赞 Alex 5/23/2012
maven-compiler-plugin 2.4 无法识别“argLine”。它仅支持“compilerArgument”,这给出错误:<compilerArgument>-XX:MaxPermSize=256m</compilerArgument> [ERROR] 执行 javac 失败,但无法解析错误:javac:无效标志:-XX:MaxPermSize=256m 用法:javac <选项> <源文件>
0赞 qwerty 2/11/2014
如果编译阶段的 permgen 用完,请在 maven-compiler-plugin 上设置 <compilerArgument>。如果单元测试的 permgen 设置 <argLine> 在 maven-surefire-plugin 中用完
69赞 4 revs, 4 users 77%Peter #20

人们常犯的错误是认为堆空间和permgen空间是一样的,这根本不是真的。堆中可能还有很多剩余空间,但仍然可能在 permgen 中耗尽内存。

PermGen 中 OutofMemory 的常见原因是 ClassLoader。每当一个类被加载到 JVM 中时,它的所有元数据以及 Classloader 都保存在 PermGen 区域中,当加载它们的 Classloader 准备好进行垃圾回收时,它们将被垃圾回收。如果 Classloader 有内存泄漏,那么它加载的所有类都将保留在内存中,并在重复几次后导致 permGen 内存不足。典型的例子是 Tomcat 中的 Java.lang.OutOfMemoryError:PermGen Space

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

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

评论

3赞 Deckard 1/20/2012
如何传递参数??我找不到.我的 tomcat 版本是 .-XX:MaxPermSize and -XX:PermSizecatalina.bat5.5.26
0赞 Amit 9/4/2014
如何找到类加载器的内存泄漏?你推荐任何工具吗?
0赞 Barett 4/24/2015
@amit有关工具建议,请参阅社区 wiki 对此问题的回答。
0赞 Zeb 10/19/2016
@Deckard进入 Tomcat/bin 目录并运行tomcat6w.exe。在“Java”选项卡下,将参数添加到“Java 选项”框中。点击“确定”
5赞 Nikem #21

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

29赞 5 revs, 2 users 91%prayagupd #22

当我使用 eclipse ide 时,我向 VM 参数添加了(您可以尝试哪种效果最好)。在大多数 JVM 中,默认的 PermSize 约为 64MB,如果项目中有太多的类或大量的 String,内存就会耗尽。-XX: MaxPermSize = 128m

对于日食,在答案中也有描述。

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

enter image description here

第 2 步打开启动 Conf 并添加到现有 VM 参数的末尾。-XX: MaxPermSize = 128m

enter image description here

评论

1赞 Chris Sim 3/7/2017
感谢您的最佳详细回答(注意:单击“打开启动配置”以打开“编辑配置”窗口...但我使用了以下参数:“-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled”
8赞 2 revs, 2 users 67%Lucky #23
  1. 从 Tomcat 的 bin 目录中打开 tomcat7w,或在开始菜单中键入 Monitor Tomcat (将打开一个选项卡式窗口,其中包含各种服务信息)。
  2. 在 Java 选项文本区域中,附加以下行:

    -XX:MaxPermSize=128m
    
  3. 将“初始内存池”设置为“1024”(可选)。
  4. 将“最大内存池”设置为 1024(可选)。
  5. 单击“确定”。
  6. 重新启动 Tomcat 服务。
14赞 Edwin Buck #24

现在最简单的答案是使用 Java 8。

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

请记住,如果您不希望 Java 8 抱怨它们什么都不做,就必须删除所有非标准的 JVM 启动参数。-XXPermGen...=...

评论

0赞 bluish 8/7/2014
您好,这个答案已经给出了:stackoverflow.com/a/22897121/505893。为清楚起见,请删除您的答案。如果需要,您可以改进我提到的答案。谢谢;)
6赞 Edwin Buck 8/7/2014
@bluish 谢谢你指出这一点;然而,这个答案在谈论 OutOfMemoryExceptions 和泄漏元数据时完全是横向的。它也没有提到删除 PermGen 选项的非常重要的要点。简而言之,我不确定我是否会改进答案,而是重写它。如果只是快速修饰,我会不那么犹豫,但看起来这不仅仅是快速修饰,我不想冒犯原作者。尽管如此,这个答案列表还是一团糟的狗晚餐,也许无论如何杀死我的帖子是最好的。
17赞 2 revs, 2 users 80%faisalbhagat #25

1) 增加 PermGen 内存大小

首先要做的就是把永久生成堆空间的大小变大。这不能用通常的 –Xms(set initial heap size) 和 –Xmx(set maximum heap size) JVM 参数来完成,因为如前所述,永久生成堆空间与常规 Java 堆空间完全分开, 这些参数为这个常规的 Java 堆空间设置了空间。但是,可以使用类似的参数(至少在 Sun/OpenJDK jvms 中)来使永久生成堆的大小更大:

 -XX:MaxPermSize=128m

默认值为 64m。

2) 启用扫描

另一种永久处理此问题的方法是允许卸载类,这样您的 PermGen 就不会用完:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

过去,像这样的东西对我有用。不过,有一件事是,使用这些会有很大的性能权衡,因为 permgen 扫描会为您提出的每个请求或类似的东西发出额外的 2 个请求。您需要在使用与权衡之间取得平衡。

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

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

评论

0赞 leomeurer 10/18/2014
@faisalbhagat faisalbhagat.blogspot.com/2014/09/ 的好帖子......
0赞 hdost 4/16/2015
选项 2 很棒,但请注意,它不应该在生产环境中使用。通常,最好仅将其保留在开发环境中。但是,PermGen 从 Java 8 openjdk.java.net/jeps/122 开始被删除
7赞 3 revs, 3 users 67%Darshan #26

Perm 生成空间错误是由于使用了大空间而不是 jvm 提供的空间来执行代码而发生的。

在 UNIX 操作系统中,此问题的最佳解决方案是更改 bash 文件上的某些配置。以下步骤解决了该问题。

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

使用以下值创建变量:JAVA_OTPS

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

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

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

2赞 NIKHIL CHAURASIA #27

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

每当我尝试运行 mvn clean package 命令时,它都会显示以下错误并发生“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 空间

我尝试了上述所有有用的提示和技巧,但不幸的是,没有一个对我有用。 对我有用的东西在下面逐步描述:=>

  1. 前往您的pom.xml
  2. 寻找<artifactId>maven-surefire-plugin</artifactId>
  3. 添加一个新元素,然后添加子元素,如下所示 =><configuration><argLine>-Xmx512m -XX:MaxPermSize=256m

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

希望对您有所帮助,祝您编程愉快:)

3赞 sendon1982 #28

在这种情况下,第一步是检查是否允许 GC 从 PermGen 卸载类。标准 JVM 在这方面是相当保守的——类生来就是为了永生。因此,一旦加载,即使没有代码再使用它们,类也会保留在内存中。当应用程序动态创建大量类并且长时间不需要生成的类时,这可能会成为一个问题。在这种情况下,允许 JVM 卸载类定义可能会有所帮助。这可以通过向启动脚本添加一个配置参数来实现:

-XX:+CMSClassUnloadingEnabled

默认情况下,这设置为 false,因此要启用它,您需要在 Java 选项中显式设置以下选项。如果启用 CMSClassUnloadingEnabled,GC 也会扫描 PermGen 并删除不再使用的类。请记住,仅当使用以下选项启用 UseConcMarkSweepGC 时,此选项才有效。因此,在运行 ParallelGC 或 Serial GC 时,请确保通过指定以下命令将 GC 设置为 CMS:

-XX:+UseConcMarkSweepGC
20赞 5 revs, 2 users 95%Santosh Jadi #29

空格消息表示永久生成在内存中的区域已耗尽。java.lang.OutOfMemoryError: PermGen

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

Java 内存分为不同的区域,如下图所示:

enter image description here

元空间:一个新的内存空间诞生了

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

好消息是,这意味着不再有 java.lang.OutOfMemoryError: PermGen 空间问题,并且您不再需要使用 Java_8_Download 或更高版本来调整和监控此内存空间。

评论

0赞 srk 1/18/2022
MetaSpace也可以去 OutOfMemory
3赞 2 revsAlejandro Pablo Tkachuk #30

分配 Tomcat 更多内存不是正确的解决方案。

正确的解决方案是在销毁并重新创建上下文后进行清理(热部署)。解决方案是阻止内存泄漏。

如果您的 Tomcat/Webapp 服务器告诉您无法注销驱动程序 (JDBC),请注销它们。这将阻止内存泄漏。

您可以创建一个 ServletContextListener 并在您的web.xml中配置它。下面是一个示例 ServletContextListener:

import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.apache.log4j.Logger;

import com.mysql.jdbc.AbandonedConnectionCleanupThread;

/**
 * 
 * @author alejandro.tkachuk / calculistik.com
 *
 */
public class AppContextListener implements ServletContextListener {

    private static final Logger logger = Logger.getLogger(AppContextListener.class);

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        logger.info("AppContextListener started");
    }

    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        logger.info("AppContextListener destroyed");

        // manually unregister the JDBC drivers
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            try {
                DriverManager.deregisterDriver(driver);
                logger.info(String.format("Unregistering jdbc driver: %s", driver));
            } catch (SQLException e) {
                logger.info(String.format("Error unregistering driver %s", driver), e);
            }

        }

        // manually shutdown clean up threads
        try {
            AbandonedConnectionCleanupThread.shutdown();
            logger.info("Shutting down AbandonedConnectionCleanupThread");
        } catch (InterruptedException e) {
            logger.warn("SEVERE problem shutting down AbandonedConnectionCleanupThread: ", e);
            e.printStackTrace();
        }        
    }
}

在这里,您可以在web.xml中对其进行配置:

<listener>
    <listener-class>
        com.calculistik.mediweb.context.AppContextListener 
    </listener-class>
</listener>