JDK8起,Hotspot JVM 废弃永久代(PermGen),同时将类元数据存储在本地内存,称之为元空间(Metaspace),而字符串常量池以及类的静态变量则存储在堆区。
为什么要废弃永久代
- 新类元数据的分配将受可用本机内存量的限制,而不是固定的由-XX:MaxPermSize参数指定的值,无论是默认值还是在命令行中指定的值。
- 简化 Full GC 的前置(JEP 156)
- 合并JRockit的一部分,JRockit没有永久代
注意: 将字符串常量池和类静态变量移至Java堆可能会导致内存不足异常或GC数量增加。用户可能需要对-Xmx进行一些调整。
什么是元空间(metaspace)
元空间是VM用于存储类的元数据的一块非堆空间的本地内存
什么时候分配内存(allocate)
加载类的时候由类加载器分配

什么时候释放内存(release)
卸载类加载器时释放内存,即发生在以下步骤之后才会释放
- 所有该类加载器加载的所有类没有存活的实例
- 没有引用指向该类加载器及其加载的类
- 该类加载器及其加载的类正常GC

注意: “释放内存”不代表将内存返回给OS,该内存全部或一部分继续保留在JVM中,可以将其重用于将来的类加载。不完全释放内存给OS就会造成碎片的产生,所以使用Metaspace会造成碎片,导致内存浪费
相关VM参数
- -XX:MetaspaceSize=${limit}:触发GC的阈值
- -XX:MaxMetaspaceSize=${limit}:Metaspace的最大值,超过则OOM(默认受本机内存大小限制)
- -XX:+UseCompressedOops:开启压缩对象指针(oops:ordinary object pointers)
- -XX:+UseCompressedClassPointers:开启压缩类指针(默认打开)
- -XX:CompressedClassSpaceSize:压缩类空间的大小,超过则OOM(仅当开启压缩类指针时生效、默认1G)