在 Java7之前,JVM 内存中有一个叫做 PermGen的区域,JVM 用来保存它的类。在 爪哇8中,它被移除并被称为 元空间的区域所取代。
PermGen 和 Metaspace 之间的 最重要的区别是什么?
我所知道的唯一区别是不能再抛出 java.lang.OutOfMemoryError: PermGen space,而且 VM 参数 MaxPermSize被忽略。
java.lang.OutOfMemoryError: PermGen space
MaxPermSize
再见,再见 PermGen,你好 Metaspace
PermGen 已被完全清除。
Metaspace 垃圾收集 -一旦类元数据的使用达到 MaxMetaspaceSize,就会触发死类和类加载器的垃圾收集。
MaxMetaspaceSize
占用的空间 Metadata不再与 Java heap相连,metadata现在已经移动到本机内存中的一个区域称为 Metaspace。
Metadata
Java heap
metadata
Metaspace
简而言之,
因为类元数据是从本机内存中分配的,所以最大可用空间就是总的可用系统内存。因此,您将不再会遇到 OOM errors,并且最终可能会溢出到交换空间中。
OOM errors
删除 PermGen并不意味着您的类装入器泄漏问题已经消失。因此,是的,您仍然必须监视您的消耗并相应地进行计划,因为泄漏将最终消耗您的整个本机内存。
PermGen
其他一些文章,包括分析: Link1、 Link2和 这个
从用户的角度来看,主要的区别在于 默认情况下自动增加元空间的大小(取决于底层操作系统提供的大小) ,而 PermGen 总是有一个固定的最大大小。您可以使用 JVM 参数为 Metaspace 设置一个固定的最大值,但是不能使 PermGen 自动增加。
在很大程度上,这只是一个名称的改变。在引入 PermGen 时,没有 Java EE 或动态类(un)加载,所以一旦加载了一个类,它就会停留在内存中,直到 JVM 关闭——因此就是 永久的生成。现在类可以在 JVM 的生命周期内加载和卸载,因此 Metaspace 对于保存元数据的区域更有意义。
它们都包含 java.lang.Class实例,并且都受到 ClassLoader 泄漏的影响。唯一不同的是,使用 Metaspace 默认设置,需要更长的时间直到你注意到症状(因为它会自动增加尽可能多) ,也就是说,你只是把问题推得更远而没有解决它。OTOH 我想操作系统内存耗尽的影响可能比仅仅耗尽 JVM PermGen 更严重,所以我不确定这是否是一个很大的改进。
java.lang.Class
无论您使用的是带有 PermGen 的 JVM 还是带有 Metaspace 的 JVM,如果您正在进行动态类卸载,那么您应该采取措施防止类加载器泄漏,例如使用我的 ClassLoader 防泄漏库。
简而言之,如果不受 -XX:MaxMetaspaceSize的限制,元空间大小会根据加载类元数据的需要自动增加本机内存
-XX:MaxMetaspaceSize
我是来让事情简单化的。
什么是 PermGen: PermGen 是一个独立于主内存堆的特殊堆空间。 Java7: PermGen 是 JVM 跟踪已加载类的元数据的空间。 Java 8: PermGen 被 Metaspace 取代,它能够根据加载类元数据的需求自动增加本机内存。
元空间