设置 MetaspaceSize 的指南 - java 8

Posted

技术标签:

【中文标题】设置 MetaspaceSize 的指南 - java 8【英文标题】:Guidelines to set MetaspaceSize - java 8 【发布时间】:2016-07-27 16:28:07 【问题描述】:

对于 64 位服务器,MetaspaceSize 的默认值是多少?官方文档里没找到。

我观察到,在服务器 JVM 进程中,有时 GC 频率会变高并不断增长。如果我重新启动服务几次,它会恢复稳定。我认为这是由于 JRE 升级。

JVM 堆最大大小设置为 6GB,但是当出现此问题时,我们看到仅使用了 3GB 堆。元空间增长很小,几乎总是满的。我尝试将元空间增加到 1GB,它提高了吞吐量。

我认为发生的情况是 Metaspace 默认设置为非常低的值,因此 GC 启动。每次 GC 发生时,高水位标记都会不断增加(再次增加非常低的量)。

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

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

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

If the committed space available for class metadata as a percentage of the total committed space for class metadata is greater than MaxMetaspaceFreeRatio, then the high-water mark will be lowered. If it is less than MinMetaspaceFreeRatio, then the high-water mark will be raised.

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

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

【问题讨论】:

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version -XX:+UseG1GC | grep Metaspace 我认为 Metaspace 默认设置为非常低的值,因此 GC 启动”——你为什么这么认为?您的解释没有暗示为什么首先应该归咎于元空间,而不仅仅是一般的堆(或可用 RAM)。 @Holger 我已经更新了描述,详细说明了为什么我认为元空间是问题所在。元空间不是第一个受到指责的人。 好问题。我们也对答案感兴趣。我们最近在 java 8 中开发了一个新的 webapp,在部署到服务器后发现它使用了超过 2.5 GB 的 Headspace 和 90 GB 的肉空间并加载了超过 17 K 的类。所以我们也有兴趣了解如何为 Java 8 webapps 调整 VM @Savior 你不需要UnlockDiagnosticVMOptions 来找出Metaspace 的那些默认 值。 【参考方案1】:

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

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

java -XX:+PrintFlagsFinal -version | grep MetaspaceSize

将产生:

size_t MetaspaceSize = 21807104 // 20MB

这意味着当Metaspace 到达20MB 时会触发Full GC,如果你能避免它,那就太好了。

考虑到元空间可以容纳多少数据(方法、注释等),在我看来20MB 是一个非常小的值。不幸的是,选择一个正确的值并不容易。

您有两个选择,启用 gc logging -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

并在应用程序运行至少一天后从Non-class space 获取值,恕我直言。

Metaspace的控制方法还有很多其他设置,你可以这样找到:

java -XX:+PrintFlagsFinal -version | grep Metaspace

【讨论】:

【参考方案2】:

我认为最有趣的问题是#3,所以我先回答那个问题。我接近它的方法是使用以下设置在 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 的评论几乎回答了您关于如何为您的实现确定默认元空间设置的前 2 个问题...为了完整起见,我将其包含在此处:

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”

【讨论】:

【参考方案3】:

从 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 对用于类元数据的本机内存量设置上限。”

WildFly 应用服务器将standalone.conf 中的元空间选项分别设置为 96 MB / 256 MB,如下所示:

... -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m ...

但是,MaxMetaspaceSize 在大型生产应用程序中可能需要更大,因为它需要包含应用程序中所有已加载类的元数据,并且您可能希望为 MetaspaceSize 指定更高的值以避免早期垃圾回收。

有关如何凭经验确定元空间设置的说明,另请参阅 @Eugene 的回答。

【讨论】:

这是错误的,Metaspace没有设置初始也不最小空间。 @Eugene,你能再澄清一点吗?我没有提到Metaspace,只有MetaspaceSizeMaxMetaspaceSize。你的意思是XX:MetaspaceSize 没有效果,即使Oracle docs 记录它?如果是,您能解释一下您为什么这么认为或参考经验测试吗? 我的错,我想说MetaspaceSize,即使你提到的文章也说“高水位”,不是初始或最小尺寸,你的陈述是错误的。 感谢您的澄清!请注意,“设置元空间的初始大小”是 Java Performance: The Definitive Guide 一书第 398 页的逐字副本。如果有误,您能否建议对 @987654339 的正确描述@ 会吗? @Eugene,现在我在下面看到了你的答案,我之前没有注意到。写得很好,给了我+1!我会更新我的答案并参考你的答案。

以上是关于设置 MetaspaceSize 的指南 - java 8的主要内容,如果未能解决你的问题,请参考以下文章

元空间大小

F460光猫配置指南

Selenium Grid操作使用指南

Android开发权威指南的图书目录

翻·《java虚拟机指南》-开个头

10.系统内存溢出问题