为什么 Java 8 移除了永久代(PermGen)并引入了元空间(Metaspace)?

Sherwin.Wei Lv8

为什么 Java 8 移除了永久代(PermGen)并引入了元空间(Metaspace)?

回答重点

Java 8 移除永久代并引入元空间,主要是为了解决 PermGen 固定大小、容易导致内存溢出、GC 效率低的问题。元空间使用本地内存,具备更灵活的内存分配能力,提升了垃圾收集和内存管理的效率。

扩展知识

PermGen 的局限性

  • 固定大小:永久代的内存空间大小在 JVM 启动时是固定的,容易出现 内存溢出(OutOfMemoryError),尤其是在动态加载大量类时。
  • 类和方法的存储限制:永久代用于存放类的元数据(类信息、方法等),其容量受限,导致某些应用特别是在大量动态生成类或使用大量第三方库时,容易出现内存管理问题。
  • GC 效率低:永久代内大部分存放的类的元数据是都是被使用的,不是垃圾对象,因此无法被回收,回收的效率很低。

Metaspace 的改进

  • 使用本地内存:元空间使用的是 本地内存(Native Memory),而不是 JVM 的堆内存,这样使得内存的分配更加灵活,避免了 PermGen 固定大小带来的局限性。
  • 自动调整大小:元空间可以根据应用的需要自动扩展大小,从而降低了出现 OutOfMemoryError 的风险,提升了内存使用的灵活性和效率。
  • 性能提升:元空间(在堆外)减少了 GC 对类元数据的影响,避免了频繁回收 PermGen 时的停顿,改善了 JVM 的整体性能。

如何监控和调整元空间的大小

JVM 提供了 -XX:MetaspaceSize-XX:MaxMetaspaceSize 的参数来控制元空间的初始和最大大小。如果不设置,元空间会根据需要动态扩展,通常情况下不需要手动调整,但对于特定的大型应用,建议进行调优以避免内存问题。

官方对移除的动机解释

官方写了:因为 JRockit 没有永久代,而 JRockit 要和 Hotspot 融合,所以把 Hotspot 永久代给去了。

其实永久代之前的存在就有点尴尬,归堆管但是实际上回收效率很低,你听听这名字永久代,不就是对象几乎是永久存在吗?

而且有永久代的话,如果永久代满了也会触发 full gc,触发了回收但是回收率又很低,所以很不划算。

因此官方借着和 JRockit 合并就把永久代也干掉,用元空间代替。元空间放在堆外,至少没堆内内存的限制了。

Comments