Перейти к основному содержимому

Изучение флагов настройки JVM

· 5 мин. чтения

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.

Значения по умолчанию для некоторых флагов могут отличаться на разных платформах, что показано в последнем столбце. Например, продукт означает, что установка флага по умолчанию едина для всех платформ; продукт pd означает, что установка флага по умолчанию зависит от платформы. Управляемые значения могут динамически изменяться во время выполнения.

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

Например, мы можем проверить исходный код HotSpot JVM на GitHub или даже в их репозитории Mercurial , а затем:

>> 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) {

Здесь мы ищем все файлы, содержащие строку PrintFlagsFinal . Найдя ответственные файлы, мы можем осмотреться и посмотреть, как работает этот конкретный флаг.

6. Заключение

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