«1. Обзор

Можно настроить HotSpot JVM с помощью различных параметров настройки. Поскольку существуют сотни таких флагов, отслеживание их и их значений по умолчанию может быть немного сложным.

В этом уроке мы познакомим вас с несколькими способами обнаружения таких флагов настройки и научимся с ними работать.

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.

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.

3.1. Diagnostic Flags

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:

>> 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. Экспериментальные флаги

Чтобы также видеть экспериментальные опции, мы должны добавить флаг UnlockExperimentalVMOptions:

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

3.3. Флаги JVMCI

Начиная с Java 9, интерфейс компилятора JVM или JVMCI позволяет нам использовать компилятор, написанный на Java, такой как Graal, в качестве динамического компилятора.

Чтобы увидеть параметры, связанные с 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. Документация и Исходный код

Одно дело найти правильное имя флага. Выяснить, что делает этот конкретный флаг под капотом, — совсем другая история.

Один из способов узнать такие подробности — просмотреть документацию. Например, документация для команды java в разделе спецификации инструментов JDK — отличное место для начала.

Иногда никакая документация не может сравниться с исходным кодом. Следовательно, если у нас есть имя определенного флага, мы можем изучить исходный код JVM, чтобы узнать, что происходит.

Например, мы можем проверить исходный код JVM HotSpot на 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, а также научились нескольким приемам для более эффективной работы с ними.