元空间(Metaspace)
元空间是JVM用于存储类元数据(class metadata)的一块内存区域。
类元数据是Java类运行时表现形式,基本上包含Java类所需的全部信息。
java.lang.Class是生活在Java堆中的Java对象,但类元数据不是Java对象,也不生活在Java堆中。它们位于Java堆之外的本地内存区域中。该区域称为Metaspace。
1.类元数据(class metadata)
它是Java在运行时已加载类的模型/模版,以便动态加载,链接,JIT编译和执行Java代码。
包含:
Klass
—-Java类运行时在JVM内部的表示。这包括vtable
和itable
。- 方法元数据(method_info)—- 类文件中结构描述,包含字节码,异常表,常量等。
- 常量池
- 注解信息
- 等等
2.元空间何时被分配
- 元空间的分配和类加载相关。
- 类加载器加载类时将该类的元数据放入元空间内。
特别注意:不同的类加载器加载同一个类是产生的元数据是不同的。
3.元空间何时被回收/释放
类分配的元空间由其类加载器拥有。仅在卸载该类加载器时才释放它。
反过来说,只有在以下情况才会发生(请参阅:JLS 12.7。卸载类和接口)。
- 此加载器加载的所有类都不再具有活动实例
- 没有对这些类和它类加载器的引用
- GC运行
而且,“释放元空间”并不一定意味着将内存返回给操作系统(OS)。
该内存的全部或一部分可以保留在JVM中;可以将其重新用于将来的类加载,但目前在JVM进程中仍未使用。
该部分的大小主要取决于元空间的碎片化程度—-元空间中已使用和未使用部分的紧密交错程度。同样,Metaspace(压缩类空间)的一部分将完全不返回给操作系统。
-XX:MaxMetaspaceSize
确定允许元空间增长的最大提交大小。默认情况下是无限的。-XX:CompressedClassSpaceSize
确定元空间的一个重要部分(压缩类空间)的虚拟大小。它的默认值为1G
4.元空间和GC
仅当GC确实运行并卸载类加载器时才释放元空间。因此,当在常规Java堆中GC收效甚微的情况下,运行GC清理陈旧的类元数据还是有意义的。在两种情况下会触发由元空间引起的GC:
- 分配元空间时:JVM设置了一个阈值,如果不超过该阈值,它将不会通过触发GC而是先尝试收集旧的类加载器(从而重新使用其元空间)来增大元空间。那就是Metaspace GC阈值。它可以防止Metaspace陈旧元数据的增长。该阈值上下移动,根据元空间总大小而定。
- 当遇到元空间OOM时(达到MaxMetaspaceSize上限时,或者当我们用尽压缩类(
CompressedClassSpaceSize
)空间时),JVM将尝试使用GC来纠正这种情况。如果它实际上卸载了类加载器,那么这样做就可以了,否则,即使我们有足够的Java堆,也可能会陷入一个糟糕的GC周期。
参考: