1. 简介
在本篇快速指南中,我们将探讨 Java 环境中 PermGen 和 Metaspace 内存区域的主要区别。
需要明确的是,从 Java 8 开始,Metaspace 正式取代了 PermGen,带来了不少显著的变化。
2. PermGen
PermGen(Permanent Generation,永久代)是一块独立于主堆内存之外的特殊堆空间。
JVM 使用这块内存来存储类的元数据信息。此外,所有的静态内容(如静态方法、基本类型变量以及静态对象的引用)也都存放在这里。
PermGen 还包含了字节码、类名、JIT 编译后的优化信息等。在 Java 7 之前,字符串常量池(String Pool)也位于 PermGen 中,但这种方式存在明显的局限性,我们曾在字符串池相关文章中提到过其固定大小带来的问题。
默认情况下,32 位 JVM 的 PermGen 最大内存为 64MB,64 位为 82MB。
当然,你可以通过以下 JVM 参数调整其大小:
-XX:PermSize=[size]
:设置 PermGen 初始或最小大小-XX:MaxPermSize=[size]
:设置 PermGen 最大大小
⚠️ 从 JDK 8 开始,Oracle 完全移除了 PermGen 区域。因此,如果你在 Java 8 及以上版本中使用这些参数,会收到如下警告:
>> java -XX:PermSize=100m -XX:MaxPermSize=200m -version
OpenJDK 64-Bit Server VM warning: Ignoring option PermSize; support was removed in 8.0
OpenJDK 64-Bit Server VM warning: Ignoring option MaxPermSize; support was removed in 8.0
...
由于 PermGen 空间有限,它常常是引发著名的 OutOfMemoryError
的元凶之一。究其原因,主要是早期的类加载器(Class Loaders)未能被正确回收,从而导致内存泄漏。
最终结果就是我们在开发环境中频繁遇到 内存溢出错误,尤其是在频繁创建新类加载器时。
3. Metaspace
简单来说,Metaspace 是从 Java 8 开始引入的新一代内存空间,用来替代旧的 PermGen 区域。最核心的区别在于其内存管理机制。
具体而言,Metaspace 默认使用本地内存(native memory),并能自动扩展。
我们也可以通过一些新的 JVM 参数进行调优:
MetaspaceSize
和MaxMetaspaceSize
:用于设置 Metaspace 的上限MinMetaspaceFreeRatio
:GC 后空闲空间占比的最小值MaxMetaspaceFreeRatio
:GC 后空闲空间占比的最大值,防止空间过度收缩
此外,Metaspace 的引入也为垃圾回收机制带来了改善。当类元数据使用量接近最大 Metaspace 大小时,垃圾回收器会自动触发清理无用类的操作。
✅ 因此,相比 PermGen,Metaspace 显著降低了出现 OutOfMemoryError
的概率。
尽管如此,我们仍需对 Metaspace 进行监控和调优(参考 JVM 调优指南),以避免潜在的内存泄漏问题。
4. 小结
本文简要介绍了 PermGen 和 Metaspace 内存区域,并重点对比了它们之间的差异。
PermGen 仍在 JDK 7 及更早版本中存在,而 Metaspace 提供了更加灵活、可靠的内存管理机制,更适合现代应用的需求。