了解元空间和类空间 GC 日志条目

了解元空间和类空间 GC 日志条目

原连接:https://poonamparhar.github.io/understanding-metaspace-gc-logs/
了解元空间和类空间 GC 日志条目
2021 年 11 月 30 日
在这篇文章中,我想分享一些关于 Metaspace 和 Compressed class space 的细节,以及如何阅读和解释相关的 GC 日志信息。

元空间
元空间是存储类元数据的本机内存区域。当一个类被 JVM 加载时,它的元数据(即它在 JVM 中的运行时表示)被分配到元空间中。

随着越来越多的类被加载,元空间占用率会增加。并且,当类加载器及其所有加载的类在 Java 堆中变得不可访问时,元空间中的关联类元数据将有资格进行释放。类元数据通过垃圾回收周期进行清理。

现在,您可能会问,在运行 GC 以清理不需要的元数据之前,Metaspace 占用率可以增长多少有限制吗?就在这里。JVM 在内部为元空间占用率维护一个阈值(又名高水位线),并在分配到元空间时检查该阈值。并且,当在该阈值内无法满足特定分配时,将调用“元数据 GC 阈值”垃圾回收周期,如以下日志记录所示。

了解元空间和类空间 GC 日志条目

**请注意,此博客中的示例日志是使用 Java 8 生成的。

有两个 JVM 选项 - MetaspaceSize和MaxMetaspaceSize可用于控制Metaspace的初始大小和最大大小。如果命令行上未明确提供这些值,则可以使用JVM 选项-XX:+PrintFlagsFinal查看 JVM 设置的值。
了解元空间和类空间 GC 日志条目

正如我们所见,MaxMetaspaceSize,如果在命令行上未配置,则几乎是无限的。MetaspaceSize设置Metaspace的初始容量和阈值,在该阈值处调用 GC 清理空间,或在无法回收足够空间时扩展容量。

元空间使用信息
让我们看一些使用 Java 程序生成的日志条目,该程序将类加载和卸载到元空间中。我用于执行程序的 JVM 选项是:

了解元空间和类空间 GC 日志条目

暂时忽略UseCompressedClassPointers选项;我们将在下一节中讨论这一点。

在运行时,Java 程序会遇到几个“元数据 GC 阈值”GC。让我们仔细检查一个这样的日志记录。
了解元空间和类空间 GC 日志条目

在这里,我们可以看到在这次特定的 Full GC 之前,Metaspace 占用率为 410659K,而在 GC 之后,占用率没有变化。括号中的数字表示新保留的元空间大小,即 456704K。

由于我们添加了-XX:+PrintHeapAtGC选项,GC 之前和之后的内存使用信息也会被打印出来,并帮助我们了解为什么会调用此 GC 以及元空间大小如何随此特定集合而变化。

了解元空间和类空间 GC 日志条目

从上面的 Metaspace 细节来看,在 GC 之前,JVM 已经预留了 456704K 并已提交 455424K 用于元数据分配。元空间使用量为 410659K。这里要注意的一件有趣的事情是容量,它充当 Metaspace 的内部高水位线。当在该阈值内无法满足特定元数据分配请求时,将调用 GC 以清理并在元空间中腾出一些空间。而且,如果该 GC 无法提供足够的可用空间,则会提交更多内存并提高容量。在本例中,此阈值设置为 455416K,其中 410659K 已在使用中。在导致此 Full GC 发生的容量限制内无法满足新的元数据分配。

GC后调整Metaspace的reserved、committed、容量边界,以满足元数据空间需求。我们可以在下一次 GC 事件之前记录的“Before GC”详细信息中找到新值。
了解元空间和类空间 GC 日志条目

上述Metaspace日志条目显示,在GC调用#16之后,保留空间和提交空间分别增加到759808K和759040K。高水位线也提升到了759024K,使用量从上次GC后的410659K增加到了685064K。

压缩的类空间
我们也可以有一个单独的空间作为元空间的一部分来存储元数据的类部分。这个单独的空间称为Compressed class space,其中的类部分元数据是使用 Java 对象的 32 位偏移量引用的。压缩的类空间在 Thomas Stuefe 的博客文章中解释得非常漂亮:https

上一篇:垃圾回收相关算法


下一篇:Java JVM区域划分、运行时内存、GC