设置MetaspaceSize的准则-Java 8

A.R*_*K.S 7 java memory-leaks out-of-memory java-8 metaspace

64位服务器的MetaspaceSize的默认值是什么?我在官方文档中找不到它。

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

JVM Heap的最大大小设置为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。.我有三个问题:

  1. 64位服务器上的默认MetaspaceSize是什么?
  2. 默认比率是什么:MaxMetaspaceFreeRatio,MinMetaspaceFreeRatio设置为?答:它显示最小为40,最大为70
  3. 如何确定一个Metaspacesize值?

Eug*_*ene 12

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

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

java -XX:+PrintFlagsFinal -version | grep MetaspaceSize
Run Code Online (Sandbox Code Playgroud)

将产生:

size_t MetaspaceSize = 21807104 // 20MB
Run Code Online (Sandbox Code Playgroud)

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

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

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

[Full GC (Metadata GC Threshold) ...]
Run Code Online (Sandbox Code Playgroud)

并从这些中了解您需要设置什么以及如何设置。

或者开始这个过程:

java -XX:NativeMemoryTracking=detail
Run Code Online (Sandbox Code Playgroud)

连接到PID通过:

jcmd <YourJVMPID> VM.metaspace
Run Code Online (Sandbox Code Playgroud)

并找到这样的行:

 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
Run Code Online (Sandbox Code Playgroud)

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

关于如何控制还有各种其他设置Metaspace,您可以这样找到:

java -XX:+PrintFlagsFinal -version | grep Metaspace
Run Code Online (Sandbox Code Playgroud)


小智 6

我认为最有趣的问题是#3,所以我会先回答这个问题。我接近它的方法是使用以下设置在打开 gc 日志记录的情况下运行我的应用程序 24 小时:

-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCCause
-XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCApplicationConcurrentTime
-Xloggc:gc.log
Run Code Online (Sandbox Code Playgroud)

然后我这样做了:

grep Metaspace gc.log
Run Code Online (Sandbox Code Playgroud)

并看到“使用”值迅速增长到 80M ......所以我将 MetaspaceSize 设置为 100M

-XX:MetaspaceSize=100M
Run Code Online (Sandbox Code Playgroud)

瞧 - 由于元空间,不再有 gcs。

看起来@Pillar 的评论几乎回答了您关于如何为您的实现确定默认元空间设置的前两个问题......为了完整性,我将其包括在此处:

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version -XX:+UseG1GC | grep Metaspace
Run Code Online (Sandbox Code Playgroud)

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

看:

https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/thinkations.html

具体来说,底部的部分说,“MetaspaceSize 的默认大小取决于平台,范围从 12 MB 到大约 20 MB”


mrt*_*rts 5

从 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 ...
Run Code Online (Sandbox Code Playgroud)

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

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