У JVM много параметров, и при запуске программы Java через командную строку, например java -jar app.jar, часто указываются различные их опции. Многие не понимают, когда именно используются -D, -X и -XX и чем отличаются эти опции JVM.

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

Главные ответы  —  в конце статьи.

Категории опций JVM

В JVM фактически поддерживается три типа опций: стандартные, нестандартные  —  также называемые дополнительными  —  и расширенные.

Опций так много потому, что JVM  —  это просто спецификация с различными реализациями: HotSpot, OpenJ9, GraalVM, Azul Zing и другими.

Их опции различаются, но некоторые опции поддерживаются всеми реализациями JVM. Это стандартные опции.

Стандартные опции

Введите в консоли java, и вы увидите не только руководство по использованию команды java, но и все стандартные опции, поддерживаемые виртуальной машиной Java по умолчанию на вашем компьютере:

~$ java
Usage: java [options] <mainclass> [args...]
(to execute a class)
or java [options] -jar <jarfile> [args...]
(to execute a jar file)
or java [options] -m <module>[/<mainclass>] [args...]
java [options] --module <module>[/<mainclass>] [args...]
(to execute the main class in a module)
or java [options] <sourcefile> [args]
(to execute a single source-file program)

Arguments following the main class, source file, -jar <jarfile>,
-m or --module <module>/<mainclass> are passed as the arguments to
main class.

where options include:

-zero to select the "zero" VM
-dcevm to select the "dcevm" VM
-cp <class search path of directories and zip/jar files>
-classpath <class search path of directories and zip/jar files>
--class-path <class search path of directories and zip/jar files>
A : separated list of directories, JAR archives,
and ZIP archives to search for class files.
-p <module path>
--module-path <module path>...
A : separated list of directories, each directory
is a directory of modules.
--upgrade-module-path <module path>...
A : separated list of directories, each directory
is a directory of modules that replace upgradeable
modules in the runtime image
--add-modules <module name>[,<module name>...]
root modules to resolve in addition to the initial module.
<module name> can also be ALL-DEFAULT, ALL-SYSTEM,
ALL-MODULE-PATH.
--enable-native-access <module name>[,<module name>...]
modules that are permitted to perform restricted native operations.
<module name> can also be ALL-UNNAMED.
--list-modules
list observable modules and exit
-d <module name>
--describe-module <module name>
describe a module and exit
--dry-run create VM and load main class but do not execute main method.
The --dry-run option may be useful for validating the
command-line options such as the module system configuration.
--validate-modules
validate all modules and exit
The --validate-modules option may be useful for finding
conflicts and other errors with modules on the module path.
-D<name>=<value>
set a system property
-verbose:[class|module|gc|jni]
enable verbose output for the given subsystem
-version print product version to the error stream and exit
--version print product version to the output stream and exit
-showversion print product version to the error stream and continue
--show-version
print product version to the output stream and continue
--show-module-resolution
show module resolution output during startup
-? -h -help
print this help message to the error stream
--help print this help message to the output stream
-X print help on extra options to the error stream
--help-extra print help on extra options to the output stream
-ea[:<packagename>...|:<classname>]
-enableassertions[:<packagename>...|:<classname>]
enable assertions with specified granularity
-da[:<packagename>...|:<classname>]
-disableassertions[:<packagename>...|:<classname>]
disable assertions with specified granularity
-esa | -enablesystemassertions
enable system assertions
-dsa | -disablesystemassertions
disable system assertions
-agentlib:<libname>[=<options>]
load native agent library <libname>, e.g. -agentlib:jdwp
see also -agentlib:jdwp=help
-agentpath:<pathname>[=<options>]
load native agent library by full pathname
-javaagent:<jarpath>[=<options>]
load Java programming language agent, see java.lang.instrument
-splash:<imagepath>
show splash screen with specified image
HiDPI scaled images are automatically supported and used
if available. The unscaled image filename, e.g. image.ext,
should always be passed as the argument to the -splash option.
The most appropriate scaled image provided will be picked up
automatically.
See the SplashScreen API documentation for more information
@argument files
one or more argument files containing options
-disable-@files
prevent further argument file expansion
--enable-preview
allow classes to depend on preview features of this release
To specify an argument for a long option, you can use --<name>=<value> or
--<name> <value>.

Хотя результат выполнения этой команды остается малопонятным, уже видны опции:

  • -cp для указания пути к классу;
  • -version для вывода информации о версии Java;
  • -D для настройки системных свойств;
  • -X для вывода справочной информации о нестандартных  —  дополнительных  —  опциях;

Вот появились и упомянутые ранее -D и -X. Здесь даже сообщается, что -D  —  это стандартная опция JVM, которой в Java задаются системные свойства в виде пар «ключ-значение» -D<name>=<value>.

Например, с помощью -Duser=Alice задается простое системное свойство, где ключ  —  user, а значение  —  Alice. Значение user получается далее в программе:

System.getProperty("user"); //Alice

Значение этого свойства переопределяется через код:

System.setProperty("user", "Bob");

Итак, -D  —  это стандартная опция JVM для задания системных свойств.

Нестандартные опции

Командой java напрямую получаем и все нестандартные опции, поддерживаемые JVM:

$ java -X

-Xbatch disable background compilation
-Xbootclasspath/a:<directories and zip/jar files separated by :>
append to end of bootstrap class path
-Xcheck:jni perform additional checks for JNI functions
-Xcomp forces compilation of methods on first invocation
-Xdebug does nothing. Provided for backward compatibility.
-Xdiag show additional diagnostic messages
-Xfuture enable strictest checks, anticipating future default.
This option is deprecated and may be removed in a
future release.
-Xint interpreted mode execution only
-Xinternalversion
displays more detailed JVM version information than the
-version option
-Xlog:<opts> Configure or enable logging with the Java Virtual
Machine (JVM) unified logging framework. Use -Xlog:help
for details.
-Xloggc:<file> log GC status to a file with time stamps.
This option is deprecated and may be removed in a
future release. It is replaced by -Xlog:gc:<file>.
-Xmixed mixed mode execution (default)
-Xmn<size> sets the initial and maximum size (in bytes) of the heap
for the young generation (nursery)
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
-Xnoclassgc disable class garbage collection
-Xrs reduce use of OS signals by Java/VM (see documentation)
-Xshare:auto use shared class data if possible (default)
-Xshare:off do not attempt to use shared class data
-Xshare:on require using shared class data, otherwise fail.
This is a testing option and may lead to intermittent
failures. It should not be used in production environments.
-XshowSettings show all settings and continue
-XshowSettings:all
show all settings and continue
-XshowSettings:locale
show all locale related settings and continue
-XshowSettings:properties
show all property settings and continue
-XshowSettings:vm
show all vm related settings and continue
-XshowSettings:system
(Linux Only) show host system or container
configuration and continue
-Xss<size> set java thread stack size
-Xverify sets the mode of the bytecode verifier
Note that option -Xverify:none is deprecated and
may be removed in a future release.
--add-reads <module>=<target-module>(,<target-module>)*
updates <module> to read <target-module>, regardless
of module declaration.
<target-module> can be ALL-UNNAMED to read all unnamed
modules.
--add-exports <module>/<package>=<target-module>(,<target-module>)*
updates <module> to export <package> to <target-module>,
regardless of module declaration.
<target-module> can be ALL-UNNAMED to export to all
unnamed modules.
--add-opens <module>/<package>=<target-module>(,<target-module>)*
updates <module> to open <package> to
<target-module>, regardless of module declaration.
--limit-modules <module name>[,<module name>...]
limit the universe of observable modules
--patch-module <module>=<file>(:<file>)*
override or augment a module with classes and resources
in JAR files or directories.
--source <version>
set the version of the source in source-file mode.

These extra options are subject to change without notice.

Опции, которые начинаются с -X, являются нестандартными. Заметили в выводе две знакомые опции? Это -Xms<size> и -Xmx<size>.

Этими двумя параметрами задается размер кучи виртуальной машины Java: первым  —  исходный и минимальный размер кучи, вторым  —  максимальный.

Например, с -Xms100m -Xmx1g исходный размер кучи задается 100 Мб, а максимальный  —  1 Гб.

Нестандартные опции, перечисленные в выходных данных, не обязательно поддерживаются всеми JVM.

Это опции, поддерживаемые установленной на компьютере виртуальной машиной JAVA. Поддержка нестандартных опций тесно связана с конкретной реализацией JVM, об их изменении не сообщается.

Расширенные опции

Расширенные опции начинаются с -XX. Разработчики обычно настраивают ими поведение, производительность или вывод отладки виртуальной машины Java. В зависимости от типа параметра расширенные опции разделяются на две категории: булевы и с параметрами.

Булевы опции

Булевы опции  —  это простые переключатели, им не требуются параметры. Вы можете включить функцию с помощью +, например -XX:+Option, и отключить с помощью -, например -XX:-Option.

Так, в HotSpot JVM встраивание метода включается с -XX:+Inline. Для повышения производительности в HotSpot это делается по умолчанию, отключается же встраивание метода с помощью -XX:-Inline.

Опции с параметрами

Другому типу расширенных опций требуется задать соответствующие значения параметров, как правило, в виде: -XX:OptionName=OptionValue. Рассмотрим примеры:

  • -XX:ErrorFile=file.log: когда возникает неустранимая ошибка, виртуальной машине Java предписывается записать сведения об ней в file.log;
  • -XX:TreadStackSize=256k: задается размер стека потока 256k;
  • -XX:MaxHeapSize=1g: максимальный размер кучи ограничивается 1GB, это все равно что -Xmx1g;

Как просмотреть все расширенные опции JVM

Команды, приведенные в этой части статьи, применимы к HotSpot JVM. Аналогичная функциональность поддерживается и другими реализациями JVM.

Некоторые значения опций настраиваются виртуальной машиной Java автоматически на основе конфигурации компьютера и другой информации.

Исходные, еще не автонастроенные в JVM значения опций показываются с помощью -XX:+PrintFlagsInitial, актуальные действительные их значения в JVM  —  с помощью -XX:+PrintFlagsFinal, а заданные пользователем или виртуальной машиной Java  —  с помощью -XX:+PrintCommandLineFlags.

-XX:+PrintFlagsInitial и -XX:+PrintFlagsFinal

Посредством -XX:+PrintFlagsFinal выводятся окончательные значения опций, принятые в JVM при запуске кода Java, в -XX:+PrintFlagsInitial же выводятся их значения по умолчанию  —  еще до изменений со стороны JVM.

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

Начнем с java -XX:+PrintFlagsFinal -version:

$ java -XX:+PrintFlagsFinal -version
[Global flags]
// ...
size_t AsyncLogBufferSize = 2097152 {product} {default}
intx AutoBoxCacheMax = 128 {C2 product} {default}
intx BCEATraceLevel = 0 {product} {default}
bool BackgroundCompilation = true {pd product} {default}
size_t BaseFootPrintEstimate = 268435456 {product} {default}
intx BiasedLockingBulkRebiasThreshold = 20 {product} {default}
intx BiasedLockingBulkRevokeThreshold = 40 {product} {default}
intx BiasedLockingDecayTime = 25000 {product} {default}
intx BiasedLockingStartupDelay = 0 {product} {default}
// ...
openjdk version "17.0.5" 2022-10-18
OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04)
OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing)

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

Первая строка  —  [Global flags], каждая последующая  —  элемент конфигурации JVM, последние строки  —  это сведения о версии JDK, эквивалент вывода java -version.

Каждая строка между первой и последними тремя  —  опция. В ее составе пять столбцов:

  • Первый столбец  —  тип опции, например intx.
  • Второй  —  ее название, например AsyncLogBufferSize.
  • Третий  —  это =. В некоторых версиях JDK этим = указывается значение по умолчанию, а :=  —  переопределенное значение опции. Однако согласно тестированию, в отличие от предыдущих версий JDK, в OpenJDK 17 := уже не выводится.
  • Четвертый столбец  —  значение опции.
  • В пятом описывается тип опции. Например, этим {product} указывается, что элемент конфигурации продукто-зависим и платформенно независим, {pd product}  —  что элемент конфигурации платформенно зависим, а {manageable}  —  что его значение динамически настраивается во время выполнения.
  • В шестом столбце указан источник значения четвертого столбца. Например, {default} подразумевает, что у опции сейчас значение по умолчанию, {ergonomic}  —  что опция задана автоматической настройкой JVM, а {command line}  —  что задана через командную строку.
  • Снова приводим только часть вывода. Первая строка  —  [Global flags], каждая последующая  —  элемент конфигурации JVM, последние строки  —  это сведения о версии JDK, эквивалент вывода java -version.
  • Каждая строка между первой и последними тремя  —  опция. В ее составе пять столбцов:
$ java -XX:+PrintFlagsFinal -version | grep command
bool PrintFlagsFinal = true {product} {command line}

Вообще-то имеется и седьмой столбец, но не в моей продукто-зависимой JVM  —  поддерживается он только отладочными версиями JVM:

$ java -XX:+PrintFlagsWithComments -version
Error: VM option 'PrintFlagsWithComments' is notproduct and is available only in debug version of VM.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

Подробнее  —  в исходном коде JDK.

В -XX:+PrintFlagsInitial выводятся значения по умолчанию для различных параметров JVM аналогично -XX:+PrintFlagsFinal.

В OpenJDK 17 обеими опциями выдается по 559 строк:

$ java -XX:+PrintFlagsInitial -version | wc -l559$ java -XX:+PrintFlagsFinal -version | wc -lopenjdk version "17.0.5" 2022-10-18OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04)OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing)559​

Выводы этих двух опций еще интереснее. Воспользуемся вот чем:

$ diff <(java -XX:+PrintFlagsInitial -version) <(java -XX:+PrintFlagsFinal -version)

Кроме этих 559, в HotSpot поддерживаются опции для диагностики виртуальной машины с -XX:+UnlockDiagnosticVMOptions:

$ java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version | wc -l
openjdk version "17.0.5" 2022-10-18
OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04)
OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing)
771

Некоторые опции экспериментальные, они доступны с помощью -XX:+UnlockExperimentalVMOptions:

$ java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version | w
c -l
openjdk version "17.0.5" 2022-10-18
OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04)
OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing)
891

Теперь их 891. Но это еще не все. Начиная с Java 9, благодаря JVMCI применяется интерфейс компилятора на основе Java:

Now it's 891 options! But that's still not all! Since Java 9, [JVMCI](https://openjdk.java.net/jeps/243) allows us to use a Java-based compiler interface:

-XX:+PrintCommandLineFlags

-XX:+PrintCommandLineFlags тоже очень полезный параметр.

Им выводятся опции, указанные нами в командной строке или автоматически заданные в ней виртуальной машиной Java:

java -XX:+PrintCommandLineFlags -version
-XX:ConcGCThreads=2 -XX:G1ConcRefinementThreads=8 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=62422080 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=998753280 -XX:MinHeapSize=6815736 -XX:+PrintCommandLineFlags -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC
openjdk version "17.0.5" 2022-10-18
OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04)
OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing)

Заключение

  • В JVM имеются разные типы опций параметров.
  • -D  —  стандартная опция для задания системных свойств.
  • С помощью -X задаются нестандартные опции, диапазон поддерживаемых опций зависит от конкретной реализации JVM.
  • С -XX задаются расширенные опции, которыми разработчики настраивают поведение, производительность или вывод отладки JVM. Диапазон поддерживаемых опций также зависит от конкретной реализации.
  • Булевы расширенные опции  —  это такие переключатели без параметров: + для включения функции, - для отключения. Для расширенных опций с параметрами указываются значения параметров.
  • Командой java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version просматриваются все опции, доступные в JVM.

## Стандартные опции

Стандартные опции поддерживаются всеми реализациями JVM. Введите в консоли java, и вы увидите не только руководство по использованию команды java, но и все стандартные опции, поддерживаемые виртуальной машиной Java по умолчанию на вашем компьютере.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Oliver Foster: JAVA: JVM Parameters: -D, -X, -XX—Can’t Tell the Difference?

Предыдущая статьяТипы функций и функции высшего порядка на Go