JVM 参数众多,咱们常在发动一个 Java 程序时经过指令行(例如:java -jar app.jar)指定各种参数选项。许多同学就会对此感到疑惑,为什么有时分要用 -D,有时分却要用 -X,还有些时分用的却是 -XX 呢?

JVM 参数:`-D`、`-X`、`-XX`,傻傻分不清?

今天,我就在这篇文章中讲一讲这些选项之间的差异。看完这篇文章之后,你将学到 JVM 选项的主要分类、不同分类的选项的主要用处,以及怎么找出 JVM 支撑的各种装备项。

想直接知道答案的同学能够直接跳到文章结尾。

JVM 选项分类

JVM 其实支撑三种类型的选项:规范选项(standard options)、非规范选项(non-standard options,又叫 extra-options)和高档选项(advanced options)。之所以有这么多选项,是由于 JVM 仅仅一个规范,它有不同的完成,例如 HotSpot、OpenJ9、GraalVM、Azul Zing 等。不同的 JVM 完成支撑的选项会有所不同,可是有些选项是一切的 JVM 完成都会支撑的,这类选项便是规范选项。

规范选项

规范选项是一切 JVM 完成都会支撑的。打开控制台,输入 java,你不只能看到 java 指令的运用手册,还能看到你机器上默认的 JVM 所支撑的一切规范选项:

~$ 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 是用来指定 Class Path 的
  • 选项 -version 是用来输出 Java 的版别信息的
  • 经过 -D 能够设置体系特点
  • -X 能够输出有关非规范选项(额外选项)的协助信息
  • ……

看到没有,咱们前面说到的 -D-X 都出现了。而且 Java 告知咱们, -D 是 JVM 的规范选项。

Java 答应咱们以 -D<name>=<value> 这种键值对的方式设置体系特点,例如:-Duser=Alice 就设置了简单的体系特点,它的键为 user,值为 Alice。随后,咱们就能够在程序中检索出 user 的值:

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

此外,咱们也能够经过代码覆盖这个特点的值:

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

现在咱们应该理解 -D 的用处了吧:-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>。这两个参数是用来设置 JVM 堆巨细的,前者设置的是堆巨细的初始值和最小值,而后者设置的是堆巨细的最大值。例如 -Xms100m -Xmx1g 会在发动 JVM 的时分将堆的初始巨细设置为 100MB,答应堆最多运用 1GB 的内存。

需求留意的是,上面输出的这些非规范选项并不是一切 JVM 都支撑,它们仅仅你机器上安装的 JVM 所支撑的一些通用选项。非规范选项的支撑是与 JVM 的详细完成紧密相关的,而且这些非规范选项或许在不告诉你的情况下悄悄地被改变。

高档选项

高档选项以 -XX 最初,这些选项一般用于开发者调整 JVM 的行为、功用或输出调试信息等。依据参数值类型的不同,高档选项又能够分为两类:布尔类型的选项和带参数的选项。

布尔选项

布尔类型的选项不带参数,仅仅一个开关。开关是不需求参数的,你能够经过 + 启用某个功用(-XX:+Option),而经过 - 禁用某个功用(-XX:-Option)。例如,在 HotSpot JVM 中,你能够经过 -XX:+Inline 启用办法内联。不过 HotSpot 为了进步功用,默认是敞开了办法内联的,所以你能够经过 -XX:-Inline 关闭办法内联。

带参选项

还有一类高档选项是需求设置相应的参数值的,方式一般为:-XX:OptionName=OptionValue。咱们来看一些比如:

  • -XX:ErrorFile=file.log 告知 JVM:当不行康复的错误产生时,将错误信息写入 file.log 这个文件。
  • -XX:TreadStackSize=256k线程栈的巨细设置为 256k
  • -XX:MaxHeapSize=1g 将堆的最大巨细限制为 1GB,等价于 -Xmx1g
  • ……

怎么查看 JVM 的一切高档选项

这一部分涉及的指令适用于 HotSpot JVM,其它的 JVM 完成或许也支撑相同或相似的功用。

JVM 能够自动依据机器的装备等信息调整一些选项的值,假如你想知道某些选项在 JVM 自动微调之前的初始值,那么你能够运用 -XX:+PrintFlagsInitial

假如你想知道某些选项在 JVM 中实践收效的值,你能够运用 -XX:+PrintFlagsFinal

假如你想知道哪些选项是被用户或 JVM 特意设置过,你能够运用 -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 选用 = 表明默认值,:= 表明选项的值被覆盖过。可是测验发现 OpenJDK 17 已经不会像之前的 JDK 版别那样输出 := 了。
  • 第四列是选项的值
  • 第五列是选项的类型。例如:{product} 表明该装备项是产品自带的(平台无关的),{pd product} 表明该装备项是平台相关的(platform-dependent),{manageable} 则表明装备项的值能够在运行时被动态调整。
  • 第六列表明第四列值的来源。例如:{default} 表明选项目前是默认值,{ergonomic} 表明该选项是 JVM 自动微调设置的,{command line} 表明该选项是经过指令行设置的。
$ java -XX:+PrintFlagsFinal -version | grep command
     bool PrintFlagsFinal                          = true                                      {product} {command line}

其实还有第七列,可是由于我的 JVM 是产品版别的,没有相关支撑。只有 debug 版别的 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 -l
559
$ java -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)
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 的编译器接口

$ java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+JVMCIPrintProperties -XX:+EnableJVMCI -XX:+PrintFlagsFinal -version | wc -l
908

-XX:+PrintCommandLineFlags

-XX:+PrintCommandLineFlags 也是一个十分有用的参数,它能够打印出那些咱们经过指令行指定或者 JVM 自动在指令行上设置的参数。

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 的行为、功用、输出调试信息,支撑的选项规模也跟详细的 JVM 完成有关
  • 布尔类型的高档选项是起到功用的开关作用,不带参数。运用 + 启用功用,运用 - 禁用功用;关于带参数的高档选项,需求指定参数值
  • 运用 java -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -XX:+PrintFlagsFinal -version 指令能够查看 JVM 一切的选项