1. 概要

さまざまなチューニングフラグを使用してHotSpotJVMをチューニングすることができます。 そのようなフラグは何百もあるので、それらとそれらのデフォルト値を追跡することは少し気が遠くなるかもしれません。

このチュートリアルでは、そのようなチューニングフラグを発見し、それらを操作する方法を学ぶためのいくつかの方法を紹介します。

2. Javaオプションの概要

java コマンドは、次のカテゴリに分類されるさまざまなフラグをサポートします。

  • そこにあるすべてのJVM実装でサポートされることが保証されている標準オプション。 通常、これらのオプションは、 –classpath、-cp、–version、などの日常的なアクションに使用されます。
  • すべてのJVM実装でサポートされているわけではなく、通常は変更される可能性のある追加オプション。 これらのオプションは-Xで始まります

これらの追加オプションを気軽に使用するべきではないことに注意してください。 さらに、 これらの追加オプションのいくつかはより高度で、 -XX。 

この記事全体を通して、より高度な-XXフラグに焦点を当てます。

3. JVMチューニングフラグ

グローバル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)

上に示したように、一部のフラグには、この特定のJVMバージョンのデフォルト値があります。

一部のフラグのデフォルト値は、プラットフォームによって異なる場合があります。これは、最後の列に示されています。 たとえば、 product は、フラグのデフォルト設定がすべてのプラットフォームで統一されていることを意味します。 pd product は、フラグのデフォルト設定がプラットフォームに依存することを意味します。 管理可能な値は、実行時に動的に変更できます。

3.1. 診断フラグ

ただし、 PrintFlagsFinal フラグは、すべての可能なチューニングフラグを表示するわけではありません。 たとえば、診断チューニングフラグも表示するには、UnlockDiagnosticVMOptionsフラグを追加する必要があります:

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

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

明らかに、診断オプションを含めると、さらに数百のフラグがあります。 たとえば、ネイティブメモリ追跡統計の印刷は、診断フラグの一部としてのみ使用できます。

bool PrintNMTStatistics                       = false                                  {diagnostic} {default}

3.2. 実験フラグ

実験的なオプションも表示するには、UnlockExperimentalVMOptionsフラグを追加する必要があります。

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

3.3. JVMCIフラグ

Java 9以降、JVMコンパイラインターフェイスまたは JVMCI を使用すると、動的コンパイラとしてGraalなどのJavaで記述されたコンパイラを使用できます。

JVMCIに関連するオプションを表示するには、さらにいくつかのフラグを追加し、JVMCIを有効にする必要があります。

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

ただし、ほとんどの場合、グローバル、診断、および実験のオプションを使用するだけで十分であり、私たちが考えているフラグを見つけるのに役立ちます。

3.4. すべてを一緒に入れて

これらのオプションの組み合わせは、特に正確な名前を覚えていない場合に、チューニングフラグを見つけるのに役立ちます。 たとえば、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}

この結果から、SoftRefLRUPolicyMSPerMBが探しているフラグであることが簡単に推測できます。

4. さまざまな種類のフラグ

前のセクションでは、重要なテーマであるフラグの種類について詳しく説明しました。 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

上に示したように、各フラグには特定のタイプがあります。

ブールオプションは、機能を有効または無効にするために使用されます。 このようなオプションには値は必要ありません。 それらを有効にするには、オプション名の前にプラス記号を付ける必要があります。

-XX:+PrintFlagsFinal

逆に、それらを無効にするには、名前の前にマイナス記号を追加する必要があります。

-XX:-RestrictContended

他のフラグタイプには引数値が必要です。 スペース、コロン、等号で値をオプション名から区切ることができます。または、引数がオプション名の直後に続く場合もあります(正確な構文はオプションごとに異なります)。

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

5. ドキュメントとソースコード

正しい旗の名前を見つけることは一つのことです。 その特定の旗が内部で何をしているのかを見つけることは別の話です。

この種の詳細を見つける1つの方法は、ドキュメントを確認することです。 たとえば、JDKツールの仕様セクションにあるjavaコマンドのドキュメントは開始するのに最適な場所です。

場合によっては、ソースコードに勝るドキュメントはありません。 したがって、特定のフラグの名前がわかれば、JVMソースコードを調べて何が起こっているのかを知ることができます。

たとえば、HotSpotJVMのソースコードをGitHubから、または Mercurialリポジトリからチェックアウトして、次のことを実行できます。

>> git clone [email protected]: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) {

ここでは、PrintFlagsFinal文字列を含むすべてのファイルを探しています。 責任のあるファイルを見つけたら、周りを見回して、その特定のフラグがどのように機能するかを確認できます。

6. 結論

この記事では、利用可能なほぼすべてのJVMチューニングフラグを見つける方法を確認し、それらをより効果的に処理するためのいくつかのトリックも学びました。