1. 概述

PermGen是分配给运行JVM应用程序的特殊内存区域。java.lang.OutOfMemoryError: PermGen spacejava.lang.OutOfMemoryError家族的一员,它表示资源(内存)耗尽的信号。

在这篇简短教程中,我们将探讨java.lang.OutOfMemoryError: PermGen space的成因以及如何解决这个问题。

2. Java内存类型

JVM使用两种类型的内存:栈和。栈仅用于存储基本类型和对象地址。而堆则存放对象的值。当我们谈论内存错误时,我们始终指的是堆。实际上,PermGen是堆内存的一部分,但它与JVM的主要内存分开并以不同的方式处理。重要的是理解,即使堆内存有大量的剩余空间,也可能出现PermGen内存不足的情况。

PermGen的主要作用是存储Java应用运行时的静态内容,包括但不限于静态方法、静态变量、对静态对象的引用以及类文件。

3. java.lang.OutOfMemoryError: PermGen

简单来说,当分配给PermGen的空间不足以存储对象时,就会发生这种错误。这是因为PermGen不是动态分配的,具有固定的上限容量。默认情况下,64位JVM的PermGen大小为82 MB,而旧的32位JVM为64 MB。

PermGen空间耗尽的常见原因之一是与类加载器相关的内存泄漏。因为PermGen包含类文件,而类加载器负责加载Java类。在需要多个类加载器独立部署多个应用程序的应用服务器中,类加载器问题很常见。

当应用程序被卸载,但服务器容器仍保留一个或多个类的引用时,问题就会出现。这时,类加载器本身无法被垃圾回收,导致PermGen内存被其类文件填满。另一个常见的PermGen故障原因是,应用程序在卸载后,其线程仍然运行,保持内存中的多个对象。

4. 解决错误的方法

4.1. 调整JVM参数

对于有限内存空间,首先要做的是如果可能的话增加空间。通过特定标志,可以增大默认的PermGen空间大小。对于包含数千个类或大量Java字符串的大应用,通常需要更大的PermGen空间。使用JVM参数-XX:MaxPermSize可以为这个内存区域指定更大的分配空间。

既然提到了JVM标志,我们也应该注意一个不太常用的可能导致此错误的标志。如果在启动JVM时指定-Xnoclassgc标志,会明确将类文件从待清理的实体列表中移除。在频繁加载和卸载类的应用服务器和现代框架中,这可能导致PermGen空间快速耗尽。

在较旧版本的Java中,类是堆内存的永久部分,一旦加载,它们就留在内存中。通过设置CMSClassUnloadingEnabled(对于Java 1.5)或CMSPermGenSweepingEnabled(对于Java 1.6)JVM参数,可以启用类的垃圾回收。如果是Java 1.6,还需要设置UseConcMarkSweepGCtrue,否则CMSClassUnloadingEnabled参数会被忽略。

4.2. 升级到JVM 8及以上版本

修复此类错误的另一种方法是升级到Java的新版本。从Java 8开始,PermGen已被完全替换为Metaspace,它具有自动可调整的内存空间,并具备清除无用类的高级功能。

4.3. 堆分析

在遇到内存泄漏的情况下,上述所有解决方案都无法解决问题。无论分配的内存多大,内存最终都会耗尽。即使是Metaspace也有其可用内存的限制。在某些情况下,深入的堆分析可能是唯一解决方案,可以使用VisualGC或JProfiler等工具进行。

5. 总结

在这篇文章中,我们了解了PermGen内存的作用及其与堆内存的主要区别。接着,我们探讨了java.lang.OutOfMemoryError: PermGen space的含义以及它在哪些特殊情况下触发。最后,我们关注了在解决这个独特问题时可以采取的各种解决方案。