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 参数进行调优:

  • MetaspaceSizeMaxMetaspaceSize:用于设置 Metaspace 的上限
  • MinMetaspaceFreeRatio:GC 后空闲空间占比的最小值
  • MaxMetaspaceFreeRatio:GC 后空闲空间占比的最大值,防止空间过度收缩

此外,Metaspace 的引入也为垃圾回收机制带来了改善。当类元数据使用量接近最大 Metaspace 大小时,垃圾回收器会自动触发清理无用类的操作。

✅ 因此,相比 PermGen,Metaspace 显著降低了出现 OutOfMemoryError 的概率。

尽管如此,我们仍需对 Metaspace 进行监控和调优(参考 JVM 调优指南),以避免潜在的内存泄漏问题。

4. 小结

本文简要介绍了 PermGen 和 Metaspace 内存区域,并重点对比了它们之间的差异。

PermGen 仍在 JDK 7 及更早版本中存在,而 Metaspace 提供了更加灵活、可靠的内存管理机制,更适合现代应用的需求。


原始标题:Permgen vs Metaspace in Java | Baeldung