设置MetaspaceSize的指南 - Java 8

19

64位服务器的MetaspaceSize默认值是多少?我在官方文档中找不到相关信息。

我发现在一个服务器JVM进程中,有时GC频率变高并持续增长。如果我重启服务几次,它就能恢复稳定。我认为这是由于JRE升级导致的。

JVM堆最大大小设置为6GB,但当出现这个问题时,我们只看到3GB堆被使用。Metaspace增长很少,并且几乎总是满的。我试图将Metaspace增加到1GB,这样可以提高吞吐量。

我认为正在发生的事情是默认情况下将Metaspace设置为非常低的值,因此GC启动。每次发生GC时,高水位标记都会持续增加(再次是非常小的数量)。

我想设置MetaspaceSize(不确定当前值是多少)。

Oracle文档说没有指南可以知道应该将MetaspaceSize设置为什么。但是有没有办法找出正确的值?

我从Oracle文档中得到了一个提示:

如果类元数据的已提交空间占类元数据总已提交空间的百分比大于MaxMetaspaceFreeRatio,则高水位标记将降低。如果小于MinMetaspaceFreeRatio,则高水位标记将升高。

但仍然无法弄清楚如何稳定GC...我的问题有三个:

  1. 64位服务器的默认MetaspaceSize是多少?
  2. 默认比率是什么:MaxMetaspaceFreeRatio,MinMetaspaceFreeRatio设置为什么?答案:显示Min为40,Max为70
  3. 如何决定Metaspacesize值?

2
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version -XX:+UseG1GC | grep Metaspace - Savior
“我认为发生的情况是默认情况下Metaspace设置为非常低的值,因此GC会启动。”——你为什么这样认为?你的解释并没有提到为什么首先要责怪Metaspace而不仅仅是堆(或可用RAM)一般。 - Holger
@Holger 我已经更新了说明,详细说明为什么我认为metaspace是问题所在。Metaspace并不是第一个受到指责的。 - A.R.K.S
好问题。我们也对答案感兴趣。我们最近在Java 8中开发了一个新的Web应用程序,部署到服务器后发现它使用了超过2.5 GB的头空间和90 GB的物理空间,并加载了超过17 K个类。因此,我们也有兴趣了解如何调整Java 8 Web应用程序的虚拟机。 - SGB
@Savior,你不需要使用UnlockDiagnosticVMOptions来查找Metaspace的那些默认值。 - Eugene
3个回答

17

MetaspaceSize是触发Full GC的值,它不是初始空间也不是最大空间。

默认值为20MB(至少在jdk-8jdk-13中):

java -XX:+PrintFlagsFinal -version | grep MetaspaceSize

会产生:

size_t MetaspaceSize = 21807104 // 20MB

这意味着当 Metaspace 达到 20MB 时,将触发一次 Full GC,如果可以避免它,那就更好了。

考虑到 Metaspace 可能会保存多少数据(例如方法、注释等),我认为 20MB 是一个非常小的值。不幸的是,选择正确的值并不容易。

您有两个选项,启用 gc 日志-Xlog:gc,让应用程序运行一段时间,然后找到类似以下实例:

[Full GC (Metadata GC Threshold) ...]

从中理解你需要设置什么以及如何设置。

或者从以下步骤开始:

java -XX:NativeMemoryTracking=detail

通过以下方式连接到PID

jcmd <YourJVMPID> VM.metaspace

并找到类似这样的行:

 Virtual space:
    Non-class space:        8.00 MB reserved,       4.25 MB ( 53%) committed
    Class space:            1.00 GB reserved,     512.00 KB ( <1%) committed
    Both:                   1.01 GB reserved,       4.75 MB ( <1%) committed

在我看来,至少应用程序运行了一天后,从非类空间获取值。

还有其他各种设置可以控制元空间的方式,您可以像这样找出它们:

java -XX:+PrintFlagsFinal -version | grep Metaspace

10

我认为最有趣的问题是第三个,所以我会先回答它。我的做法是使用以下设置,在应用程序启用GC日志记录后运行24小时:

-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCCause
-XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCApplicationConcurrentTime
-Xloggc:gc.log

然后我做了这个:

grep Metaspace gc.log

然后发现 "used" 值迅速增长到了 80M ... 所以我将 MetaspaceSize 设置为 100M。

-XX:MetaspaceSize=100M

完成以上步骤后,就不会再因为元空间而出现gcs了。

看起来@Pillar的评论已经基本回答了你如何确定实现中默认的元空间设置的前两个问题...为了完整起见,我在这里把它包括进来:

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version -XX:+UseG1GC | grep Metaspace

从技术上讲,@Pillar的评论并没有告诉你任何64位服务器的默认元空间大小,但这是因为你的第一个问题有点误导人。根据文档,这些默认值因实现而异。

请参见:https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/considerations.html

特别是底部部分中提到的,“MetaspaceSize的默认大小取决于平台,范围从12 MB到约20 MB”


6
自Java 8以来,以下命令行选项可以控制两个最重要的元空间设置:
- -XX:MetaspaceSize=N - 当用于类元数据的初始已提交空间达到此级别时,将引发垃圾回收;根据收集结果,该级别可能随后被提高或降低。 - -XX:MaxMetaspaceSize=N - 设置元空间的最大大小。
引用 Oracle HotSpot VM Garbage Collection Tuning Guide 的说法,
  • "当相应的Java类被卸载时,类元数据将被释放。Java类由于垃圾回收而被卸载,并且垃圾回收可能会导致卸载类和释放类元数据。当用于类元数据的空间达到一定水平(高水位标记)时,将引发垃圾回收。在垃圾回收之后,高水位标记可能会提高或降低,具体取决于从类元数据中释放的空间量。为了不会过早地引发另一次垃圾回收,高水位标记将被提高。高水位标记最初设置为命令行选项-XX:MetaspaceSize的值。[...] -XX:MetaspaceSize的默认大小因平台而异,范围从12 MB到约20 MB。"
  • "默认情况下,可以使用的用于类元数据的本机内存量是无限的。使用选项-XX:MaxMetaspaceSize来限制用于类元数据的本机内存量的上限。"
野飞服务器将standalone.conf中的元空间选项设置为96 MB / 256 MB,如下所示:
... -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m ...

然而,在大型生产应用程序中,MaxMetaspaceSize可能需要更大,因为它需要包含应用程序中加载的所有类的元数据,并且您可能希望为MetaspaceSize指定更高的值以避免早期垃圾回收。
另请参阅@Eugene的答案,了解如何经验性地确定元空间设置的说明。

1
这是错误的,Metaspace 不会设置初始空间和最小空间。 - Eugene
@Eugene,您能再解释一下吗?我没有提到Metaspace,只有MetaspaceSizeMaxMetaspaceSize。您是说即使Oracle文档中记录了XX:MetaspaceSize,它也没有任何影响吗?如果是的话,您能否解释一下为什么或者参考实证测试? - mrts
我的错,我想说的是MetaspaceSize,即使你提到的文章也说“高水位线”,而不是初始或最小大小,因此你的某个陈述是错误的。 - Eugene
感谢澄清!请注意,“设置元空间的初始大小”是从《Java性能权威指南》第398页的原文复制而来。如果有误,请问您能否提供正确的描述来说明MetaspaceSize的作用? - mrts
这是错误的,元空间不是初始值。元空间的初始值为0,没有初始元空间。请参见上面的答案。编辑或删除您的答案以避免误导。 - Francisco Melo junior
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接