测试中,遇到的错误是:

java.lang.OutOfMemoryError: PermGen space


这个错误表示 JVM 的永久代(PermGen)内存溢出,常见于 Java 7 及更早版本。PermGen 是 JVM 内存模型中用于存储类的元数据(如类定义、方法、常量池等)的一部分。

🧠 原因分析

主要原因:

  1. 加载了大量类(例如使用反射、动态代理、JSP 编译、OSGi、Groovy、Spring AOP 等)
  2. 频繁重新部署 Web 应用(在 Tomcat 中热部署导致旧类未被卸载)
  3. JVM 默认的 PermGen 空间较小

🔧 解决方案

1. 增加 PermGen 内存

在启动参数中增加以下 JVM 参数:

-XX:PermSize=128m -XX:MaxPermSize=256m


示例(Tomcat setenv.shstartup.bat):

Linux/Unix (setenv.sh):

export JAVA_OPTS="$JAVA_OPTS -XX:PermSize=128m -XX:MaxPermSize=256m"


Windows (setenv.bat):

set JAVA_OPTS=%JAVA_OPTS% -XX:PermSize=128m -XX:MaxPermSize=256m



2. 使用 -XX:+CMSClassUnloadingEnabled(配合 CMS GC)

如果你使用的是并发标记清除垃圾回收器(CMS),可以启用类卸载功能:

-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled


这有助于在 Full GC 时回收无用类的元数据,缓解 PermGen 溢出问题。


3. 升级到 Java 8+

从 Java 8 开始,永久代(PermGen)被元空间(Metaspace)取代,默认情况下 Metaspace 会自动扩展,不再有固定大小限制。

你可以通过以下参数控制 Metaspace 大小(可选):

-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m


如果你正在使用 Java 8 或更高版本,但仍看到 PermGen 错误,请检查是否设置了兼容性参数或使用了旧版工具链。


4. 检查应用是否有类泄漏

常见的类泄漏场景包括:

  • 使用自定义 ClassLoader 加载类但未正确卸载
  • Spring / Hibernate / OSGi 等框架管理不当
  • JSP 页面频繁修改导致重复编译生成新类

建议:


📌 总结

方案

描述

增加 PermGen

-XX:PermSize-XX:MaxPermSize

启用类卸载

-XX:+CMSClassUnloadingEnabled(需配合 CMS GC)

升级 Java 版本

使用 Java 8+,替换为 Metaspace

分析内存泄漏

使用内存分析工具排查类加载问题