Exploring JVM Tuning Flags – 探索JVM调优标志

最后修改: 2020年 6月 17日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

It’s possible to tune the HotSpot JVM with a variety of tuning flags. As there are hundreds of such flags, keeping track of them and their default values can be a little daunting.

我们可以用各种调整标志来调整HotSpot JVM。由于有数百个这样的标志,跟踪它们和它们的默认值可能有点令人生畏。

In this tutorial, we’re going to introduce a few ways to discover such tuning flags and learn how to work with them.

在本教程中,我们将介绍几种发现这种调谐标志的方法,并学习如何使用它们。

2. Overview of Java Options

2.Java选项概述

The java command supports a wide variety of flags falling into the following categories:

java命令支持各种各样的标志,分为以下几类。

  • Standard options that are guaranteed to be supported by all JVM implementations out there. Usually, these options are used for everyday actions such as –classpath, -cp, –version, and so on
  • Extra options that are not supported by all JVM implementations and are usually subject to change. These options start with -X

Please note that we shouldn’t use these extra options casually. Moreover, some of those additional options are more advanced and begin with -XX

请注意,我们不应该随便使用这些额外的选项。此外,这些额外的选项中有些是比较高级的,以-XX开头。

Throughout this article, we’re going to focus on more advanced -XX flags.

在这篇文章中,我们将重点讨论更高级的-XX标志。

3. JVM Tuning Flags

3.JVM调谐标志

To list the global JVM tuning flags, we can enable the PrintFlagsFinal flag as follows:

为了列出全局的JVM调整标志,我们可以启用PrintFlagsFinal标志,如下:

>> java -XX:+PrintFlagsFinal -version
[Global flags]
    uintx CodeCacheExpansionSize                   = 65536                                  {pd product} {default}
     bool CompactStrings                           = true                                   {pd product} {default}
     bool DoEscapeAnalysis                         = true                                   {C2 product} {default}
   double G1ConcMarkStepDurationMillis             = 10.000000                                 {product} {default}
   size_t G1HeapRegionSize                         = 1048576                                   {product} {ergonomic}
    uintx MaxHeapFreeRatio                         = 70                                     {manageable} {default}

// truncated
openjdk version "14" 2020-03-17
OpenJDK Runtime Environment (build 14+36-1461)
OpenJDK 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)

As shown above, some flags have default values for this particular JVM version.

如上所示,有些标志对于这个特定的JVM版本有默认值。

Default values for some flags may be different on different platforms, which is shown in the final column. For instance, the product means that the default setting of the flag is uniform across all platforms; the pd product means that the default setting of the flag is platform-dependent. The manageable values can be changed dynamically at runtime.

一些标志的默认值在不同的平台上可能是不同的,这在最后一栏中显示。例如,product意味着该标志的默认设置在所有平台上是统一的;pd product意味着该标志的默认设置与平台相关。manageable值可以在运行时动态地改变。

3.1. Diagnostic Flags

3.1.诊断标志

The PrintFlagsFinal flag, however, does not show all possible tuning flags. For instance, to also see diagnostic tuning flags, we should add the UnlockDiagnosticVMOptions flag:

然而,PrintFlagsFinalflag并没有显示所有可能的调整标志。例如,为了同时看到诊断调谐标志,我们应该添加UnlockDiagnosticVMOptionsflag:

>> java -XX:+PrintFlagsFinal -version | wc -l
557

>> java -XX:+PrintFlagsFinal -XX:+UnlockDiagnosticVMOptions -version | wc -l
728

Clearly, there are a couple hundred more flags when we’re including diagnostic options. For example, printing native memory tracking stats is only available as part of diagnostic flags:

很明显,当我们包括诊断选项时,还有几百个标志。例如,打印本地内存跟踪统计信息只作为诊断标志的一部分。

bool PrintNMTStatistics                       = false                                  {diagnostic} {default}

3.2. Experimental Flags

实验性旗帜

To also see experimental options, we should add the UnlockExperimentalVMOptions flag:

为了同时看到实验选项,我们应该添加UnlockExperimentalVMOptionsflag:

>> java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version | wc -l
809

3.3. JVMCI Flags

3.3 JVMCI标志

As of Java 9, the JVM compiler interface or JVMCI enables us to use a compiler written in Java, such as Graal, as a dynamic compiler.

从Java 9开始,JVM编译器接口或JVMCI使我们能够将用Java编写的编译器(如Graal)用作动态编译器。

To see options related to JVMCI, we should add a few more flags and also even enable the JVMCI:

为了看到与JVMCI有关的选项,我们应该多加几个标志,甚至启用JVMCI。

>> java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions \
>> -XX:+JVMCIPrintProperties -XX:+EnableJVMCI -XX:+PrintFlagsFinal  -version | wc -l
1516

Most of the time, however, using global, diagnostic, and experimental options should suffice and will help us to find the flag we have in mind.

然而,大多数时候,使用全局、诊断和实验选项应该就足够了,并会帮助我们找到我们心目中的标志。

3.4. Putting It All Together

3.4.归纳总结

These combinations of options can help us to find a tuning flag, especially when we don’t remember the exact name. For instance, to find the tuning flag related to soft references in Java:

这些选项的组合可以帮助我们找到一个调整标志,特别是在我们不记得确切名称的时候。例如,要找到与Java中软引用有关的调整标志。

>> alias jflags="java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal  -version"
>> jflags | grep Soft
size_t SoftMaxHeapSize                          = 4294967296                             {manageable} {ergonomic}
intx SoftRefLRUPolicyMSPerMB                    = 1000                                   {product} {default}

From the result, we can easily guess that SoftRefLRUPolicyMSPerMB is the flag we’re looking for.

从结果来看,我们很容易猜到SoftRefLRUPolicyMSPerMB是我们要找的标志。

4. Different Types of Flags

4.不同类型的旗帜

In the previous section, we glossed over an important subject: the flag types. Let’s take another look at the java -XX:+PrintFlagsFinal -version output:

在上一节中,我们忽略了一个重要的主题:标志类型。让我们再看一下java -XX:+PrintFlagsFinal -version 输出。

[Global flags]
    uintx CodeCacheExpansionSize                   = 65536                                  {pd product} {default}
     bool CompactStrings                           = true                                   {pd product} {default}
     bool DoEscapeAnalysis                         = true                                   {C2 product} {default}
   double G1ConcMarkStepDurationMillis             = 10.000000                                 {product} {default}
   size_t G1HeapRegionSize                         = 1048576                                   {product} {ergonomic}
    uintx MaxHeapFreeRatio                         = 70                                     {manageable} {default}
// truncated

As shown above, each flag has a specific type.

如上所示,每个标志都有一个特定的类型。

Boolean options are used to either enable or disable a feature. Such options don’t require a value. To enable them, we just have to put a plus sign before the option name:

布尔选项用于启用或禁用某个功能。这种选项不需要一个值。要启用它们,我们只需要在选项名称前加上一个加号。

-XX:+PrintFlagsFinal

On the contrary, to disable them, we have to add a minus sign before their name:

相反,要禁用它们,我们必须在它们的名字前加上一个减号。

-XX:-RestrictContended

Other flag types need an argument value. It’s possible to separate the value from the option name by a space, a colon, an equal sign, or the argument may directly follow the option name (the exact syntax differs for each option):

其他标志类型需要一个参数值。可以用空格、冒号、等号将参数值与选项名称分开,也可以将参数直接跟在选项名称后面(每个选项的具体语法都不同)。

-XX:ObjectAlignmentInBytes=16 -Xms5g -Xlog:gc

5. Documentation and Source Code

5.文件和源代码

Finding the right flag name is one thing. Finding what that particular flag is doing under the hood is another story.

找到正确的旗帜名称是一件事。找到那个特定的旗子在引擎盖下做什么是另一回事。

One way to find out these sorts of details is by looking at the documentation. For instance, the documentation for the java command in the JDK tools specification section is a great place to start.

了解这些细节的方法之一是查看文档。例如,JDK工具规范部分中的java命令的文档是一个很好的开始。

Sometimes, no amount of documentation can beat the source code. Therefore, if we have the name of a particular flag, then we can explore the JVM source code to find out what’s going on.

有时,再多的文档也比不上源代码。因此,如果我们有一个特定标志的名称,那么我们就可以探索JVM的源代码,找出其中的原因。

For instance, we can check out the HotSpot JVM’s source code from GitHub or even their Mercurial repository and then:

例如,我们可以从GitHub或甚至他们的Mercurial资源库中查看HotSpot JVM的源代码,然后。

>> git clone git@github.com:openjdk/jdk14u.git openjdk
>> cd openjdk/src/hotspot
>> grep -FR 'PrintFlagsFinal' .
./share/runtime/globals.hpp:  product(bool, PrintFlagsFinal, false,                                   
./share/runtime/init.cpp:  if (PrintFlagsFinal || PrintFlagsRanges) {

Here we’re looking for all files containing the PrintFlagsFinal string. After finding the responsible files, we can look around and see how that specific flag works.

在这里,我们要寻找所有包含PrintFlagsFinal字符串的文件。找到负责的文件后,我们可以四处看看,看看那个特定的标志是如何工作的。

6. Conclusion

6.结论

In this article, we saw how we could find almost all available JVM tuning flags and also learned a few tricks to work with them more effectively.

在这篇文章中,我们看到了如何找到几乎所有可用的JVM调优标志,也学到了一些技巧,以便更有效地使用它们。