获取不同虚拟机参数的终极方法

在学习和实践虚拟机相关知识的过程中,经常会疑问某个特性在我现在用的版本中启用了么,需要手动配置启用么?当前虚拟机有700项左右的配置参数,不同版本和模式的虚拟机默认值也是不同的,不论是查文档或是网上搜索都很难快速的找到答案,最好的办法就是自己动手寻找答案。

虚拟机类型

在只考虑Oracle的HotSpot虚拟机时,区分不同虚拟机需要考虑大版本(1.6、1.7、1.8)、小版本(u43、u162)、位数(32、64)、模式(server、client),以上任意变化都可能导致默认参数的不同,在验证一些新特性时尽量保证服务器和本地环境一致。

虚拟机模式

虚拟机(HotSpot)有client和server两种模式,分别用 -client-server 参数启用。

$ java -client -version

java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) Client VM (build 25.162-b12, mixed mode)

or

$ java -server -version

java version "1.8.0_162"
Java(TM) SE Runtime Environment (build 1.8.0_162-b12)
Java HotSpot(TM) Server VM (build 25.162-b12, mixed mode)

client和server模式一些默认值有所不同,最明显的就是server模式(jdk1.8)默认使用吞吐量优先收集器(UseParallelGC)、默认打开逃逸分析(DoEscapeAnalysis),这些配置让server模式有更好的资源利用以及长期稳定运行支持。

如果没有显式指定 -client-server 参数,虚拟机会根据运行环境是否服务器级别选择是否启用server模式,但是这让人很不放心;同时即使有时候显示指定该参数,由于当前安装版本不支持(例如jdk8u151的64位windows版本仅支持server模式),依然不会生效。如何能确认当前服务器上的虚拟机运行在server模式呢?答案是通过系统属性变量:

System.out.println(System.getProperty("java.vm.name"));

Java HotSpot(TM) Client VM
or
Java HotSpot(TM) 64-Bit Server VM

查看配置的方法

JDK1.6u21后HotSpot虚拟机提供了 -XX:+PrintFlagsFinal 用来查看最终生成的虚拟机配置参数,可以用在启动配置,甚至没有启动类时对 -version 生效(注意在有启动类时不要带 -version ,会阻挡执行后面的启动类)。

java -server -XX:+PrintFlagsFinal -version

它生的结果有5列:

Type | Name | Operator | Value | Application

如:

java -server -XX:+PrintFlagsFinal -version | grep "UseSerialGC\|UseG1GC\|UseParallelGC\|UseConcMarkSweepGC" 

bool UseConcMarkSweepGC                       = false                              {product}
bool UseG1GC                                  = false                              {product}
bool UseParallelGC                            := true                                {product}
bool UseSerialGC                              = false                              {product}

其中需要注意第三列,:= 意味着值是被修改的,= 表示默认值,其他列对使用者意义不大。

配合使用 -XX:+UnlockExperimentalVMOptions-XX:+UnlockDiagnosticVMOptions 可以解锁显示更多隐藏配置参数。

类似命令 -XX:+PrintCommandLineFlags仅展示第三列为 := 的参数,即被修改或主动设置过的参数。

类似命令 -XX:+PrintFlagsInitial仅展示第三列为 = 的参数,即默认值,意义不大。

在使用实践过程中,发现 -client 模式下 PrintFlagsFinal 显示 UseSerialGC = false ,而实际上如果打印GC信息 -XX:+PrintGCDetails 会看到[DefNew: 4416K->512K...]这样的信息,即实际上该值为true,这是一项历史bug,在jdk9修复(因为默认使用g1收集器)。

universe.cpp:

727 else { // UseSerialGC
728 // Don't assert that UseSerialGC is set here because there are cases
729 // where no GC it set and we then fall back to using SerialGC.
730 status = Universe::create_heap<GenCollectedHeap, MarkSweepPolicy>();
731 }
posted @ 2018-03-18 02:45  Jeff_p  阅读(861)  评论(0编辑  收藏  举报