1. 概述
垃圾回收是Java运行时系统识别并删除内存中未引用对象的过程,它通过清除未引用的对象、临时对象、未使用的元数据等,在内存管理中发挥着至关重要的作用。
在本教程中,我们将探索元空间和元数据GC阈值,以及如何调整它们的参数。
2. 元数据
元数据包含堆中对象的信息,包括它们的类定义、方法表和相关信息。根据Java版本的不同,JVM会将这些数据存储在永久代或元空间(Metaspace)中。
JVM依靠这些信息来执行类加载、字节码验证和动态绑定等任务。
3. PermGen和Metaspace
从Java 8开始,JVM用内存中一个名为“元空间”的新区域来存储元数据,从而取代了永久代或PermGen。
PermGen是一个固定大小的内存区域,独立于主堆,用于存储JVM加载的类和方法的元数据。它有一个固定的最大大小,一旦满了,JVM就会抛出OutOfMemoryError。
元空间的大小并非固定不变,可以根据应用程序中元数据的数量动态增长。元空间独立于主堆,位于一段本机内存(进程内存)中,它的大小仅受主机操作系统的限制。
4. 元数据GC阈值
在Java中,当我们创建一个带有元数据的对象时,它会像其他对象一样占用内存空间,JVM需要这些元数据来执行各种任务。与常规对象不同,元数据在达到特定阈值之前不会被垃圾回收。
随着Java程序执行过程中越来越多的类被动态加载,元空间就会被填满。
JVM维护元空间内容大小的阈值,当特定分配不符合该阈值时,它会触发元数据GC阈值垃圾回收周期。
5. 元数据的JVM参数
我们可以使用JVM标志(如-XX:+PrintClassHistogram和-XX:+PrintMetaspaceStatistics)来收集有关使用大量元数据内存的类的信息,并打印有关Metaspace的统计信息,例如用于类元数据的空间量。
利用这些信息,我们可以优化代码,提高元空间和垃圾回收周期的利用率。此外,我们还可以调整与元空间相关的JVM参数。
我们来看一下用于调整元数据和元空间的一些JVM参数。
5.1 -XX:MetaspaceSize=<size>
此参数用于设置分配给类元数据的初始空间量(初始高水位线)(以字节为单位),这些空间量可能引发垃圾回收并卸载类。该值是近似值,这意味着JVM也可以决定增加或减少元空间的大小。
此参数的值较大时,可确保垃圾回收发生的频率较低,该参数的默认值取决于平台,范围从12MB到20MB左右。
例如,我们可以将其设置为128兆字节:
-XX:MetaspaceSize=128m
5.2 -XX:MaxMetaspaceSize=<size>
此参数设置Metaspace的最大大小,超过此大小将引发OutOfMemory错误,此标志限制分配给类元数据的空间量,分配给此参数的值是近似值。
默认情况下,没有设置限制,这意味着Metaspace可以增长到可用本机内存的大小。
作为示例,我们将其设置为100兆字节:
‑XX:MaxMetaSpaceSize=100m
5.3 -XX:+UseCompressedClassPointers
此功能旨在通过压缩对象引用来减少64位Java应用程序的内存占用,当此参数设置为true时,JVM将对类元数据使用压缩指针,这使得JVM能够对类相关数据使用32位寻址,而不是使用完整的64位指针。
这种优化在64位架构上尤其有价值,因为它减少了类元数据的内存使用量以及对象引用所需的内存,从而有可能提高应用程序的整体性能。
压缩类指针将类空间分配与非类空间分配区分开,因此,我们有两个全局元空间上下文:一个保存Klass结构的分配(压缩类空间),另一个保存其他所有内容(非类元空间)。
值得注意的是,在最近版本的JVM中,运行64位Java应用程序时通常默认启用该标志,因此我们通常不需要明确设置此标志。
5.4 -XX:+UseCompressedOops
此JVM标志用于启用或禁用64位JVM中Java对象使用压缩指针的功能,当该参数设置为true时,JVM将使用压缩指针,这意味着对象引用将使用32位指针,而不是完整的64位指针。
使用压缩指针,只能寻址较小范围的内存,这迫使JVM使用较小的指针来节省内存。
6. 总结
在本文中,我们探讨了元数据和元空间的概念。
我们探讨了触发元数据GC阈值的原因,此外,我们还了解了元数据GC阈值以及可用于调整元空间和优化垃圾回收周期的不同JVM参数。
Post Directory
