"PermGen space 是Java虚拟机(JVM)内存模型中的一部分,主要用来存储类的元数据,如类的加载器、方法信息、常量池等。当 PermGen 区域耗尽时,可能会抛出 `OutOfMemoryError: PermGen space` 错误。这种错误通常在频繁加载或卸载类、大型应用、尤其是运行Web应用服务器如Tomcat,并且预编译大量JSP时发生。解决这个问题通常涉及调整JVM参数,增大 PermGen 区域的大小,例如设置 `-XX:MaxPermSize` 参数。此外,减少对 PermGen 的占用,比如优化第三方库的使用,也是有效策略。"
PermGen space 是早期Java版本(JDK 8之前)中的一个内存区域,它与堆内存(Heap)不同,主要负责存储类的元数据,包括类的信息、方法的元数据、常量池等。这些信息在程序运行期间是持久存在的,因此得名 Permanent Generation。然而,当PermGen空间不足时,会导致JVM无法再加载新的类,从而抛出`OutOfMemoryError: PermGen space`异常。
此问题常见于Web应用服务器,特别是那些频繁部署、重部署或预编译大量JSP的环境。例如,使用Tomcat时,如果JSP文件频繁更改或数量庞大,每次重新部署都会导致类加载器及其对应的类元数据在PermGen中积累,最终可能导致内存溢出。
为了解决 PermGen space 溢出的问题,开发者可以考虑以下措施:
1. **调整JVM参数**:通过增加 `-XX:MaxPermSize` 参数的值来增大 PermGen 区域的大小,例如设置为 `128m`。同时,可以使用 `-XX:PermSize` 设置初始大小,以避免程序启动时就出现溢出。
2. **减少 PermGen 占用**:
- 使用 proxool 代替 CGLIB,因为 CGLIB 在运行时会产生大量的代理类,消耗 PermGen 空间。
- 对于日志框架,优先选择不依赖 CGLIB 的实现,如 log4j 或者使用系统默认的日志框架。
- 如果可能,升级到不再使用 PermGen 的Java版本(JDK 8及以上),这些版本将元数据存储区域替换为 Metaspace。
3. **优化第三方库**:减少不必要的库依赖,尤其是那些可能大量生成类元数据的库。
4. **管理共享库**:确保将公共库放在 tomcat/shared/lib 目录下,让它们被所有Web应用共享,以减少每个应用单独加载的类数量。
5. **监控和调整堆大小**:除了关注 PermGen 外,还要注意 Heap 内存的分配。可以使用 `-Xms` 和 `-Xmx` 设置堆的初始大小和最大大小,而 `-Xmn` 用于设置年轻代的大小。确保这些参数设置合理,以避免 `Java heap space` 错误。
理解和管理 PermGen space 对于避免Java应用程序出现内存溢出至关重要,尤其是对于那些运行Web应用的服务器。通过调整JVM参数、优化代码和库使用,可以有效地缓解和解决这类问题。