java -version查看JDK版本,并验证安装是否成功java,会给出java命令的使用说明
-options:可选,java命令的命令行选项,多个选项使用空格分隔class:要启动的类的名称,要求得是类的完全限定名,也就是包名 + 类名,例如:com.sunrise.Hellojarfile:通过-jar选项,指定要调用的jar(Java Archive,JAR)文件的名称。
META-INF/MANIFEST.MF文件中Main-Class定义com.sunrise.HelloManifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: sunrise
Created-By: Apache Maven 3.6.1
Build-Jdk: 1.8.0_192
Main-Class: com.sunrise.Hello
args ...:传递给main方法参数,使用空格分隔plublic static的,无返回值,并接受String数组作为入参。args传递的参数,就是String数组的元素public static void main(String[] args)
javafx.application.Application的类;init()方法,然后调用start(javafx.stage.Stage)方法,以完成应用程序的启动
+/-,开启/关闭选项+开启选项、-关闭选项。-XX:+OptionName表示开启选项,-XX:-OptionName表示关闭选项-XX:-HeapDumpOnOutOfMemoryError。-XX:+HeapDumpOnOutOfMemoryError即可空格进行分隔,如-jar filename:进行分隔。例如,-Xloggc:filename,指定gc日志的文件名;-version:release,指定运行应用程序的JDK的release版本=进行分隔。例如,-XX:HeapDumpPath=path_of_the_dump_file,指定OOM时dump文件的路径-Xmxsize指定堆的最大内存,-Xmssize指定堆的初始化(最小)内存sizeDataSize的单位
某些选项需要指定data size,一般是内存大小,例如-Xmx、-Xms、-Xmn等
如果以byte为单位,则可以不给出单位后缀,只指定数值
如果以KB为单位,则需要以k或K为单位后缀
如果以MB为单位,则需要以m或M为单位后缀
如果以GB为单位,则需要以g或G为单位后缀
例如,指定堆的最大内存为8GB,其不同单位的写法如下:
-Xmx8589934592
-Xmx8388608k 或 -Xmx8388608K
-Xmx8192m 或 -Xmx8192M
-Xmx8g 或 -Xmx8G
带比例的值
官方文档中,有这样的一句话:
If you are expected to specify the percentage, then use a number from 0 to 1. For example, specify 0.25 for 25%.
但是,从笔者的已知的关于ratio的配置方式来说,有两种ratio的配置方式
一是,使用0 ~ 100,表示0% ~ 100%
例如,-XX:MaxHeapFreeRatio=percent选项,其默认值为70%,即-XX:MaxHeapFreeRatio=70。
二是,给出相对比例
例如,有名的-XX:SurvivorRatio=ratio,默认值为8,即-XX:SurvivorRatio=8。表示新生代中,eden : survivor = 8 : 1,由于survivor区有两个,整个新生代被划分为10份,survivor占整个新生代大小的1/10
survivor和eden的计算公式,总结如下(Y表示新生代的大小)
Eden = (R * Y) / (R + 1 + 1)
From = Y / (R + 1 + 1)
To = Y / (R + 1 + 1)
相对比例是如何计算的?
-XX:SurvivorRatio选项为例,明明指定的是8,意思是survivor占整个新生代的8份,两个survivor那就是16份?" ")引住-Dinput.files="file1 file2 file3" java命令版本不满足要求,并在系统上找到了一个合适实现,则会使用该合适的实现
1.x.0_u,其中x为主版本号,u为更新版本号空格表示OR,使用&表示AND,使用+表示此版本或更高版本,具体可以参考JDK官方文档-version:"1.6.0_13 1.6* & 1.6.0_10+",要求使用JRE 6u13(1.6.0_13)或者任何从从6u10(1.6.0_10+)开始的JRE 6(1.6*)新对象,是gc的主要的区域。新生代设置得过小,则会频繁的minor gc以回收新生代的内存1 MB
2 MB
hs_err_pid%p.log。其中,%p表示应用程序的进程号hs_err_pid%p.log文件,并未引起关注,这次的学习算是给笔者提了个醒;分隔;若包含空格,需要使用双引号" "关闭状态,即 -XX:-HeapDumpOnOutOfMemoryErrorjava_pid%p.hprof的文件-XX:-ExitOnOutOfMemoryError.dump为扩展类型;binary类型的扩展文件,在Linux中以.core为扩展类型,在Windows中,以.mdp为后缀-XX:-CrashOnOutOfMemoryErrorVS -XX:+CrashOnOutOfMemoryError使用如下代码触发OOM
package internet.gc;
public class GcTest {
private final static int MB = 1024 * 1024;
private final static int LEN = 12;
public static void main(String[] args) {
byte[][] buffer= new byte[LEN][];
for (int i = 0; i < LEN; i++) {
buffer[i] = new byte[1 * MB];
}
System.out.println("成功初始化byte数组");
}
}
IDEA运行时,设置VM参数如下,开启ExitOnOutOfMemoryError选项
-Xms10M -Xmx10M -XX:+ExitOnOutOfMemoryError -XX:-CrashOnOutOfMemoryError
程序运行起来后打印了如下信息,除此之外并未生成其他文件
Terminating due to java.lang.OutOfMemoryError: Java heap space
更新VM参数,开启CrashOnOutOfMemoryError选项
-Xms10M -Xmx10M -XX:-ExitOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError
程序运行起来后,打印了如下信息:
Aborting due to java.lang.OutOfMemoryError: Java heap space
#
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (debug.cpp:308), pid=52754, tid=0x0000000000002503
# fatal error: OutOfMemory encountered: Java heap space
#
# JRE version: Java(TM) SE Runtime Environment (8.0_192-b12) (build 1.8.0_192-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.192-b12 mixed mode bsd-amd64 compressed oops)
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/xxx/IdeaProjects/antlr4/hs_err_pid52754.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
从提示信息可知,生成了error文件hs_err_pid52754.log,其中52754是程序的pid。

由于系统权限限制,并未生成前面提到的text和binary类型的crash文件,需要使用ulimit -c unlimited命令进行处理
而笔者使用的用户名,无权限执行该命令,因此无法观察text和binary类型的crash文件,后续若有机会将会进行补充
总结:
ulimit -c unlimited命令开启权限查看jvm标准选项,可以使用如下命令
java 或者 java -help 或者 java -? # 其中-?与-help同义
查看jvm非标准选项,可以使用如下命令
java -X
使用-XX:+PrintFlagsInitial选项,可以打印所有-XX选项的默认值
java -XX:+PrintFlagsInitial
部分打印结果选取如下,第一列:选项的数据类型,第二列:选项名,第四列:选项的默认值,第五列:选项的类别
intx OnStackReplacePercentage = 140 {pd product}
bool LazyBootClassLoader = true {product}
uintx InitialHeapSize = 0 {product}
基于长期的观察,JVM一般会将某些选项的值更新为一个合适的初始值。例如,JDK 8中,新生代大小为-XX:NewSize被更新为89128960(85MB),而非默认值1363144
在JDK官网中,这种根据观察设置初始值的行为,被叫做ergonomics
此时,可以使用-XX:+PrintFlagsFinal查看-XX选项的实际值
# 如何不指定-version,会打印所有的标准option,影响数据的查看
java -XX:+PrintFlagsFinal -version
# 也可以指定某个Java类,这样会先打印高级选项,再执行Java应用程序
java -cp ./target/classes -XX:+PrintFlagsFinal com.sunrise.jvm.GcTest

为了表示该选项已经被JVM ergonomics或用户设置,-XX:+PrintFlagsFinal选项将在第三列的赋值符号(=)上做文章,使用:=表示该选项已经被更新过
uintx MaxHeapFreeRatio = 100 {manageable}
uintx MaxHeapSize := 4294967296 {product}
JVM中有些选项,还处于实验阶段,并未正式对外开放,因此会将其隐藏起来
例如,G1中的-XX:G1NewSizePercent=5和-XX:G1MaxNewSizePercent=60,想要更改这两个选项的默认值,需要使用-XX:+UnlockExperimentalVMOptions进行解锁
java -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=10 -XX:G1MaxNewSizePercent=75 G1test.jar
因此,如果想要查看隐藏选项的实际值,可以使用如下命令
java -server -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version
加上这两个解锁隐藏选项的参数后,打印出的选项个数从 731上涨为877
-XX:+PrintFlagsFinal既打印了未被设置值的选项,还打印了被用户或JVM ergonomics设置值的选项
有时,我们只需要查看哪些选项被设置了值。这时,可以使用-XX:+PrintCommandLineFlags打印被设置了值的选项
java -XX:+PrintCommandLineFlags -version
# 或者
java -cp ./target/classes -XX:+PrintCommandLineFlags com.sunrise.jvm.GcTest
最终,都将打印如下信息,可见JDK 8为堆大小、垃圾回收器等设置了一个合适的值,而非使用默认值
-XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
最开始,笔者想在执行应用程序时,打印出用户或JVM ergonomics设置过的CommandLine Flags
整个java命令如下:
# 设置堆的初始和最大size位10MB,程序运行起来后,将触发OOM
# 打印用户或JVM ergonomics设置过的CommandLine Flags
# 将详细的gc日志(包含时间戳)重定向到gc.log中
java -cp ./target/classes -Xms10M -Xmx10M -XX:+PrintCommandLineFlags -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:./gc.log com.sunrise.jvm.GcTest
最终,执行结果如下,并生成了gc.log

gc.log的内容如下,可以发现gc.log中,打印了一些与jdk、执行环境等有关的信息,还打印了CommandLine flags,以及gc事件的详情
Java HotSpot(TM) 64-Bit Server VM (25.192-b12) for bsd-amd64 JRE (1.8.0_192-b12), built on Oct 6 2018 09:36:52 by "java_re" with gcc 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
Memory: 4k page, physical 16777216k(19984k free)
/proc/meminfo:
CommandLine flags: -XX:InitialHeapSize=10485760 -XX:MaxHeapSize=10485760 -XX:+PrintCommandLineFlags -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
2022-11-13T13:27:03.348-0800: 0.108: [GC (Allocation Failure) --[PSYoungGen: 1466K->1466K(2560K)] 7610K->7610K(9728K), 0.0048048 secs] [Times: user=0.01 sys=0.01, real=0.01 secs]
2022-11-13T13:27:03.353-0800: 0.113: [Full GC (Ergonomics) [PSYoungGen: 1466K->1288K(2560K)] [ParOldGen: 6144K->6144K(7168K)] 7610K->7432K(9728K), [Metaspace: 2475K->2475K(1056768K)], 0.0024963 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2022-11-13T13:27:03.355-0800: 0.116: [GC (Allocation Failure) --[PSYoungGen: 1288K->1288K(2560K)] 7432K->7440K(9728K), 0.0005330 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
2022-11-13T13:27:03.356-0800: 0.116: [Full GC (Allocation Failure) [PSYoungGen: 1288K->1276K(2560K)] [ParOldGen: 6152K->6144K(7168K)] 7440K->7420K(9728K), [Metaspace: 2475K->2475K(1056768K)], 0.0018582 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
PSYoungGen total 2560K, used 1358K [0x00000007bfd00000, 0x00000007c0000000, 0x00000007c0000000)
eden space 2048K, 66% used [0x00000007bfd00000,0x00000007bfe53bb8,0x00000007bff00000)
from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
to space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
ParOldGen total 7168K, used 6144K [0x00000007bf600000, 0x00000007bfd00000, 0x00000007bfd00000)
object space 7168K, 85% used [0x00000007bf600000,0x00000007bfc000e8,0x00000007bfd00000)
Metaspace used 2506K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 269K, capacity 386K, committed 512K, reserved 1048576K
从执行结果和gc日志不难发现:
-XX:+PrintGCDetails会打印很多额外的信息(JDK版本、执行环境、CommandLine Flags)等,可以不用额外指定-XX:+PrintCommandLineFlags -XX:+PrintGCTimeStamps选项,猜测:-XX:+PrintGCDateStamps一旦指定,-XX:+PrintGCTimeStamps也会被指定-XX:+PrintGC选项,猜测:-XX:+PrintGCDetails一旦指定,-XX:+PrintGC也会被指定jps命令加上-v选项,可以打印启动应用程序时的CommandLine Flags
jps -v
例如,查看Presto服务启动时的CommandLine Flags
jps -v | grep "PrestoServer"
执行结果如下:

如下的jinfo命令,可以查看所有CommandLine Flags
jinfo -flags pid
基于上面的Presto服务,进程号为100656,通过jinfo查看其CommandLine Flags

同时,还可以查看指定的flag的值。注意: 需要切换到启动该应用程序的用户,否则会报错:pid: Unable to open socket file: target process not responding or HotSpot VM not loaded
jinfo -flag option_name pid
该Presto服务使用G1垃圾回收器,查看选项UseG1GC的结果如下:

除此之外,jinfo命令还可以动态修改option的值
jinfo -flag [+|-]name pid # 动态修改boolean类型的option的值
jinfo -flag <name>=<value> pid # 动态修改option的值