在 JDK 8 中,元空间(Metaspace)确实可以触发 GC(垃圾回收)。
背景知识
在 JDK 8 之前,Java 使用永久代(PermGen)来存储类的元数据(如类的字节码、名称、常量池等)。在 JDK 8 中,永久代被移除了,取而代之的是元空间。元空间不是在堆内存中分配的,而是使用本地内存(native memory)。
什么时候元空间会触发 GC
元空间可以触发一种特定的垃圾回收,称为类卸载(Class Unloading)。当类的元数据充满元空间时,JVM 会尝试回收未被使用的类及其关联的类加载器。这意味着如果元空间的使用接近其最大限制(可以通过 -XX:MaxMetaspaceSize
参数设置),JVM 会触发 Full GC 来进行类卸载,从而释放元空间中的内存。
参数设置
-XX:MetaspaceSize
:设置元空间的初始大小,当达到这个大小时会触发垃圾回收来进行类卸载和压缩。-XX:MaxMetaspaceSize
:设置元空间的最大大小,如果没有设置,元空间会根据需要动态增长,直到达到系统内存的上限。
示例
以下是一个简单示例,展示如何通过参数控制元空间大小并观察 GC 行为:
public class MetaspaceExample {
public static void main(String[] args) {
for (int i = 0; i < 100000; i++) {
createClass();
}
}
private static void createClass() {
// 使用 ASM 或 CGLIB 动态生成类
// 这里仅作示例,可以使用第三方库来动态生成类
}
}
运行这个程序并使用以下 JVM 参数:
java -XX:MetaspaceSize=16m -XX:MaxMetaspaceSize=64m -XX:+PrintGCDetails MetaspaceExample
在上述参数设置中,-XX:+PrintGCDetails
可以输出详细的 GC 日志,以便观察元空间相关的 GC 行为。
GC 日志
在 GC 日志中,您可以看到类似以下的输出,当元空间达到 MetaspaceSize
时会触发垃圾回收:
[Full GC (Metadata GC Threshold) ...
这表明垃圾回收是由于元空间的元数据达到阈值而触发的。
总结
在 JDK 8 中,元空间是会触发 GC 的,特别是在类卸载过程中。当元空间达到某个阈值时,JVM 会进行 Full GC 来回收未使用的类及其元数据。通过调整元空间的相关参数,可以控制元空间的大小和垃圾回收行为。