Lesson 14 of 14
JDK Command-Line Tools
The JDK ships with the tools needed to compile, package, run, and diagnose a Java program without an IDE. This lesson covers the tools in the order a program moves through them: build, run, then inspect a running JVM. All output below comes from JDK 25 on Linux.
| Tool | Purpose |
|---|---|
java |
Start a JVM, run a class, a jar, or a single source file |
javac |
Compile .java files to .class files |
jar |
Create, list, and extract jar archives |
jshell |
Evaluate Java snippets interactively or from a script |
jps |
List running JVM processes |
jcmd |
Send a diagnostic command to a running JVM |
jstack |
Print the thread stacks of a running JVM |
jmap |
Print a class histogram of the heap |
jstat |
Print garbage collector and memory statistics over time |
jfr |
Read and summarize Flight Recorder files |
JAVA_TOOL_OPTIONS |
Environment variable that adds JVM options to every java start |
The diagnostic tools (jps, jcmd, jstack, jmap, jstat) attach to a JVM owned by the same operating system user. Process ids and timestamps differ on every run, so the outputs below replace process ids with PID where a command prints one.
Example 1: java -version
The first check on any machine is which JVM java starts. The command prints the version and the build.
java -version
java --versionopenjdk version "25.0.4.1" 2026-08-18
OpenJDK Runtime Environment (build 25.0.4.1+1-1-24.04.4-Ubuntu)
OpenJDK 64-Bit Server VM (build 25.0.4.1+1-1-24.04.4-Ubuntu, mixed mode, sharing)
openjdk 25.0.4.1 2026-08-18
OpenJDK Runtime Environment (build 25.0.4.1+1-1-24.04.4-Ubuntu)
OpenJDK 64-Bit Server VM (build 25.0.4.1+1-1-24.04.4-Ubuntu, mixed mode, sharing)The first form is the older single-dash option and writes to standard error. The second form is the double-dash option and writes to standard output, so it can be piped or captured with $(...). The first line names the vendor build and the release. The last line names the VM and its mode: mixed mode means the JVM both interprets and compiles code, and sharing means class data sharing is active, which shortens startup.
If several JDKs are installed, JAVA_HOME and the PATH order decide which one runs. The tools in this lesson all come from the same bin directory, so a jcmd from one JDK may fail to attach to a JVM started by another. Matching versions avoids that.
Example 2: java single-file source launch
Since JDK 11, java can compile and run one source file in memory, with no separate javac step. This suits small scripts and examples.
public class Hello {
public static void main(String[] args) {
System.out.println("Hello from " + (args.length > 0 ? args[0] : "nobody"));
}
}java Hello.java worldHello from worldThe argument ends in .java, so java compiles the file in memory and runs the first class declared in it. Everything after the file name goes to the program as args. No .class file is written to disk.
The mode has limits. It handles one file only, so a program split across several source files needs javac. Options for the compiler and the JVM go before the file name, as in java -Xmx64m Hello.java.
Example 3: javac -d
A project with a package needs a compile step that writes class files into a directory tree. The -d option names that directory.
package com.example;
public class Greeter {
public String greet(String name) {
return "hello, " + name;
}
}package com.example;
public class App {
public static void main(String[] args) {
System.out.println("App " + new Greeter().greet("jar"));
}
}These two files live in src/com/example/. The App block depends on Greeter in another file, so the example checker skips it. Compile them into out and run the result:
javac -d out src/com/example/*.java
find out -type f | sort
java -cp out com.example.Appout/com/example/App.class
out/com/example/Greeter.class
App hello, jar| Option | Meaning |
|---|---|
-d out |
Write class files under out, creating one directory per package segment |
-cp out |
Class path: directories and jars where java looks for classes |
--release 21 |
Compile against the Java 21 API and language level, whatever JDK runs javac |
The -d directory is created if it is missing. The directory layout mirrors the package name, which is why com.example.App becomes out/com/example/App.class. java then takes the fully qualified class name, not a file path.
Example 4: jar create and list
A jar is a zip file with a manifest. It packages a class tree into one file that java -jar can start.
jar --create --file app.jar --main-class com.example.App -C out .
jar --list --file app.jar
java -jar app.jarMETA-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/App.class
com/example/Greeter.class
App hello, jar| Option | Meaning |
|---|---|
--create (-c) |
Create a new archive |
--file (-f) |
Name of the archive |
--main-class (-e) |
Write the entry point into the manifest, so java -jar knows which class to start |
-C out . |
Change into out and add everything under it, so entries start at com/ and not at out/com/ |
--list (-t) |
List the entries |
--extract (-x) |
Extract the entries into the current directory |
The tool added META-INF/MANIFEST.MF on its own. The short form jar tf app.jar lists the same entries, and jar cfe app.jar com.example.App -C out . is the short form of the create command. A common mistake is running jar from the parent directory without -C. The entries then begin with out/, and java -jar fails to find com.example.App.
Example 5: jshell
jshell evaluates Java statements and expressions one at a time, with no class or main method. It is a read-eval-print loop (REPL), a program that reads one input, runs it, and prints the result.
cat > cmds.jsh <<'EOF2'
int x = 6 * 7;
String s = "jdk".toUpperCase();
System.out.println(x + " " + s);
/exit
EOF2
jshell -s cmds.jsh42 JDKThe file mixes Java snippets with jshell commands. Lines that start with / are jshell commands: /exit ends the session, /vars lists variables, /imports lists imports, and /help lists the rest. The -s option selects the concise feedback mode, so assignments do not print a line such as x ==> 42 for each snippet. Without a file argument, jshell opens an interactive prompt that reads from the terminal.
jshell imports java.util, java.io, java.math, java.util.stream, and a few other packages by default, so snippets like List.of(1, 2, 3) need no import line. The tool suits checking an API call or a format string before putting it in a source file.
Target program for Examples 6 to 11
The next six tools inspect a running JVM, so they need a process to inspect. This program starts one daemon thread named worker-1 that allocates arrays in a loop and sleeps briefly, then keeps the JVM alive for ten minutes.
import java.util.ArrayList;
import java.util.List;
public class Target {
static final List<byte[]> KEEP = new ArrayList<>();
public static void main(String[] args) throws Exception {
Thread worker = new Thread(() -> {
long n = 0;
while (true) {
KEEP.add(new byte[10_000]);
if (KEEP.size() > 2000) KEEP.clear();
n++;
if (n % 200 == 0) {
try { Thread.sleep(5); } catch (InterruptedException e) { return; }
}
}
}, "worker-1");
worker.setDaemon(true);
worker.start();
Thread.sleep(600_000);
}
}Compile it, start it in the background, and keep its process id in a shell variable:
javac Target.java -d tout
java -cp tout Target &
PID=$!$! holds the process id of the last background command. The examples below use $PID. When the examples are finished, kill $PID stops the program.
Example 6: jps -l
jps lists the JVM processes of the current user. The -l option prints the main class or jar path instead of only the short class name.
jps -l7319 jdk.jcmd/sun.tools.jps.Jps
7261 TargetThe first column is the process id and varies on every run. The second column is the main class. The line for jdk.jcmd/sun.tools.jps.Jps is jps itself, because it is also a JVM.
| Option | Meaning |
|---|---|
-l |
Full main class name, or the jar path for java -jar |
-v |
JVM arguments passed to the process |
-m |
Arguments passed to main |
jps reads the same attach information the other tools use. When a JVM does not appear in the list, the usual causes are a different operating system user, a container with a separate /tmp, or the option -XX:-UsePerfData on the target.
Example 7: jcmd
jcmd is the general entry point. Run without arguments it lists JVMs. Run with a process id and a command name, it asks that JVM to run a diagnostic command and prints the result. The next four calls use help, VM.flags, Thread.print, and GC.heap_info.
The list form:
jcmdPID jdk.jcmd/sun.tools.jcmd.JCmd
PID TargetThe help command lists what the target JVM supports (trimmed to the first 27 lines; the full list is longer):
jcmd $PID helpPID:
The following commands are available:
AOT.end_recording
Compiler.CodeHeap_Analytics
Compiler.codecache
Compiler.codelist
Compiler.directives_add
Compiler.directives_clear
Compiler.directives_print
Compiler.directives_remove
Compiler.memory
Compiler.perfmap
Compiler.queue
GC.class_histogram
GC.finalizer_info
GC.heap_dump
GC.heap_info
GC.run
GC.run_finalization
JFR.check
JFR.configure
JFR.dump
JFR.start
JFR.stop
JFR.view
JVMTI.agent_load
JVMTI.data_dump
ManagementAgent.start
ManagementAgent.start_localjcmd $PID help GC.heap_info prints the description and options of one command. The list depends on the JDK version, so help is the reference for the JVM actually running.
VM.flags prints the JVM flags in effect, including values the JVM chose itself:
jcmd $PID VM.flagsPID:
-XX:-AOTInvokeDynamicLinking -XX:-AOTRecordTraining -XX:-AOTReplayTraining -XX:CICompilerCount=3 -XX:ConcGCThreads=1 -XX:G1ConcRefinementThreads=4 -XX:G1EagerReclaimRemSetThreshold=16 -XX:G1HeapRegionSize=2097152 -XX:G1RemSetArrayOfCardsEntries=16 -XX:G1RemSetHowlMaxNumBuckets=8 -XX:G1RemSetHowlNumBuckets=8 -XX:InitialHeapSize=224395264 -XX:-IntelJccErratumMitigation -XX:MarkStackSize=4194304 -XX:MarkStackSizeMax=536870912 -XX:MaxHeapSize=3588227072 -XX:MaxNewSize=2151677952 -XX:MinHeapDeltaBytes=2097152 -XX:MinHeapSize=8388608 -XX:NonNMethodCodeHeapSize=5836800 -XX:NonProfiledCodeHeapSize=122912768 -XX:ProfiledCodeHeapSize=122912768 -XX:ReservedCodeCacheSize=251662336 -XX:+SegmentedCodeCache -XX:SoftMaxHeapSize=3588227072 -XX:-THPStackMitigation -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseG1GC -XX:X86ICacheSync=3No heap or collector option was given, so every value comes from the JVM's own sizing. -XX:+UseG1GC shows the collector, and -XX:MaxHeapSize=3588227072 shows the heap limit in bytes, chosen from the machine memory. The exact flags depend on the machine and the JDK build.
Thread.print prints all thread stacks. The filter below keeps the entry for worker-1:
jcmd $PID Thread.print | grep -A8 '"worker-1"'"worker-1" #23 [7282] daemon prio=5 os_prio=0 cpu=218.76ms elapsed=2.99s tid=0x00007f5c18148290 nid=7282 waiting on condition [0x00007f5bfcd85000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleepNanos0(java.base@25.0.4.1/Native Method)
at java.lang.Thread.sleepNanos(java.base@25.0.4.1/Thread.java:509)
at java.lang.Thread.sleep(java.base@25.0.4.1/Thread.java:540)
at Target.lambda$main$0(Target.java:15)
at Target$$Lambda/0x0000000033040210.run(Unknown Source)
at java.lang.Thread.runWith(java.base@25.0.4.1/Thread.java:1487)
at java.lang.Thread.run(java.base@25.0.4.1/Thread.java:1474)The header gives the thread name, id, priority, CPU time, and age. nid is the operating system thread id; here it equals the number in the [7282] field. The state TIMED_WAITING (sleeping) and the top frames show that this sample caught the thread inside Thread.sleep, called from line 15 of Target.java. The id, the address values, and the timings differ on every run.
GC.heap_info prints the heap layout:
jcmd $PID GC.heap_infoPID:
garbage-first heap total reserved 3504128K, committed 221184K, used 104484K [0x000000072a200000, 0x0000000800000000)
region size 2048K, 49 young (100352K), 5 survivors (10240K)total reserved is the address space set aside for the heap. committed is the memory the JVM has asked the operating system for. used is what live and not yet collected objects occupy. G1 splits the heap into regions of equal size, here 2048K, and the second line counts the young regions and survivor regions. The values change as the program allocates.
Example 8: jstack
jstack prints thread stacks, the same data as jcmd $PID Thread.print. It is the older and shorter command, and it is the usual choice when diagnosing a hang or a deadlock.
jstack $PID | grep -A6 '"worker-1"'"worker-1" #23 [7282] daemon prio=5 os_prio=0 cpu=236.98ms elapsed=3.28s tid=0x00007f5c18148290 nid=7282 waiting on condition [0x00007f5bfcd85000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleepNanos0(java.base@25.0.4.1/Native Method)
at java.lang.Thread.sleepNanos(java.base@25.0.4.1/Thread.java:509)
at java.lang.Thread.sleep(java.base@25.0.4.1/Thread.java:540)
at Target.lambda$main$0(Target.java:15)
at Target$$Lambda/0x0000000033040210.run(Unknown Source)The dump begins with a line Full thread dump OpenJDK 64-Bit Server VM (...), then one block per thread. Two or three dumps taken a few seconds apart show whether a thread is moving or stuck. A thread that shows the same stack in every dump is waiting or blocked there.
When threads deadlock on monitors, the dump ends with a section Found one Java-level deadlock: that names each thread and the lock it holds and wants. The state BLOCKED means the thread waits for a monitor, WAITING and TIMED_WAITING mean it waits on wait, park, or sleep, and RUNNABLE means it is running or ready to run, including threads blocked in native I/O.
Example 9: jmap -histo
jmap -histo prints a histogram of objects on the heap: one row per class with an instance count and the bytes used.
jmap -histo $PID | head -8 num #instances #bytes class name (module)
-------------------------------------------------------
1: 20895 121954056 [B (java.base@25.0.4.1)
2: 172 1798000 [Ljdk.internal.vm.FillerElement; (java.base@25.0.4.1)
3: 1694 224208 java.lang.Class (java.base@25.0.4.1)
4: 8681 208344 java.lang.String (java.base@25.0.4.1)
5: 1452 163304 [Ljava.lang.Object; (java.base@25.0.4.1)
6: 2023 54024 [I (java.base@25.0.4.1)[B is the JVM name for byte[], so the top row is the arrays the worker-1 thread allocates. [I is int[], and [Ljava.lang.Object; is Object[]. The FillerElement row is a placeholder object that the collector uses to keep heap regions parseable. The table includes objects that are no longer reachable but not yet collected.
The live option forces a collection first, so the table counts only reachable objects:
jmap -histo:live $PID | head -5 num #instances #bytes class name (module)
-------------------------------------------------------
1: 9804 10876584 [B (java.base@25.0.4.1)
2: 1694 224208 java.lang.Class (java.base@25.0.4.1)
3: 8680 208320 java.lang.String (java.base@25.0.4.1)The byte[] total dropped from about 122 MB to about 11 MB, because most arrays were garbage. The live option triggers a full collection, which pauses the application. On a production process, take the plain histogram first. Comparing two histograms taken some minutes apart shows which class count keeps growing, which is the first clue in a memory leak search. jcmd $PID GC.class_histogram prints the same table.
Example 10: jstat -gc
jstat reads counters the JVM publishes and prints them as a table. It does not pause the program, and it can repeat at an interval.
jstat -gc $PID S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT CGC CGCT GCT
0.0 2048.0 0.0 1575.7 77824.0 22528.0 55296.0 11607.5 384.0 185.5 128.0 10.4 12 0.034 1 0.011 0 0.000 0.044The size columns are in KB. A trailing C means capacity and a trailing U means used.
| Column | Meaning |
|---|---|
S0C, S1C, S0U, S1U |
Survivor space capacity and use |
EC, EU |
Eden (new object area) capacity and use |
OC, OU |
Old generation capacity and use |
MC, MU |
Metaspace (class metadata) capacity and use |
YGC, YGCT |
Count and total seconds of young collections |
FGC, FGCT |
Count and total seconds of full collections |
CGC, CGCT |
Count and total seconds of concurrent collections |
GCT |
Total collection time in seconds |
Two other forms are common. -gcutil prints percentages, and a trailing interval and count repeat the sample:
jstat -gcutil $PID 200 3 S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT
- 76.94 81.58 20.99 48.30 8.14 12 0.034 1 0.011 0 0.000 0.044
- 100.00 90.32 34.23 48.30 8.14 13 0.040 1 0.011 0 0.000 0.050
- 84.93 91.67 38.04 48.30 8.14 14 0.041 1 0.011 0 0.000 0.051The arguments 200 3 mean one sample every 200 milliseconds, three samples. The YGC column rises from 12 to 14 while the three rows print, which shows the allocation rate of the target: two young collections in under half a second. A rising FGC count with little freed memory points to a heap that is too small or a leak. The - in S0 means that survivor space is empty in G1.
Example 11: jfr record and jfr print/summary
Java Flight Recorder (JFR) records events from inside the JVM with low overhead: GC pauses, allocation samples, method samples, lock waits, and more. jcmd starts the recording, and the jfr tool reads the file.
jcmd $PID JFR.start name=demo filename=/tmp/claude-0/cmd-l14/demo/rec.jfr duration=5s settings=profilePID:
Started recording 1. The result will be written to:
/tmp/claude-0/cmd-l14/demo/rec.jfr| Option | Meaning |
|---|---|
name=demo |
Label for the recording, used by JFR.check, JFR.dump, and JFR.stop |
filename= |
File that receives the data when the recording ends |
duration=5s |
Stop and write the file after five seconds |
settings=profile |
Use the profile event set, which samples more often than default |
After seven seconds the file exists. jfr summary counts events by type (the 17 largest types are shown):
jfr summary rec.jfr | head -25
Version: 2.1
Chunks: 1
Start: 2026-10-03 15:18:59 (UTC)
Duration: 5 s
Event Type Count Size (bytes)
=============================================================
jdk.GCPhaseParallel 2447 65021
jdk.ObjectAllocationSample 1491 20891
jdk.PromoteObjectInNewPLAB 560 9854
jdk.ModuleExport 508 5437
jdk.BooleanFlag 496 15213
jdk.ActiveSetting 376 9700
jdk.TenuringDistribution 330 3369
jdk.ModuleRequire 156 1560
jdk.InitialEnvironmentVariable 152 9106
jdk.LongFlag 137 4400
jdk.UnsignedLongFlag 93 3143
jdk.SystemProcess 91 11987
jdk.GCReferenceStatistics 88 880
jdk.MetaspaceChunkFreeListSummary 88 1584
jdk.GCPhasePauseLevel1 66 2686
jdk.UnsignedIntFlag 48 1582
jdk.InitialSecurityProperty 45 2243The summary shows what the recording holds before any event is printed. The counts vary from run to run. jfr print --events prints events of one type, matched by the full or the short name:
jfr print --events jdk.GCPhasePause rec.jfr | head -14jdk.GCPhasePause {
startTime = 15:18:59.220 (2026-10-03)
duration = 3.28 ms
gcId = 19
name = "GC Pause"
eventThread = "VM Thread" (osThreadId = 7272)
}
jdk.GCPhasePause {
startTime = 15:18:59.440 (2026-10-03)
duration = 1.24 ms
gcId = 20
name = "GC Pause"
eventThread = "VM Thread" (osThreadId = 7272)Each block is one GC pause with its start time, length, and collection id. Method samples show where the CPU time goes. The option --stack-depth 3 limits the printed stack:
jfr print --events jdk.ExecutionSample --stack-depth 3 rec.jfr | head -16jdk.ExecutionSample {
startTime = 15:18:59.083 (2026-10-03)
sampledThread = "worker-1" (javaThreadId = 23)
state = "STATE_RUNNABLE"
stackTrace = [
Target.lambda$main$0() line: 14
java.lang.Thread.run() line: 1474
]
}
jdk.ExecutionSample {
startTime = 15:18:59.193 (2026-10-03)
sampledThread = "worker-1" (javaThreadId = 23)
state = "STATE_RUNNABLE"
stackTrace = [
Target.lambda$main$0() line: 14Every sample lands on line 14, the line that allocates the array, which matches the program. The options --json and --xml print the same events in a structured form for scripts. For event sets, JMC and the viewer commands, and an async-profiler comparison, see JFR and async-profiler.
After this example, stop the target program:
kill $PIDExample 12: JAVA_TOOL_OPTIONS
JAVA_TOOL_OPTIONS is an environment variable that every JVM start reads. Its contents act as extra JVM options, and the JVM prints a notice on standard error when it uses them. This helps when the java command line cannot be edited, as with a build tool or a test runner that starts a JVM.
public class Props {
public static void main(String[] args) {
System.out.println("greeting=" + System.getProperty("greeting"));
System.out.println("maxMemoryMB=" + Runtime.getRuntime().maxMemory() / (1024 * 1024));
}
}JAVA_TOOL_OPTIONS="-Xmx64m -Dgreeting=hi" java Props.java
java Props.javaPicked up JAVA_TOOL_OPTIONS: -Xmx64m -Dgreeting=hi
greeting=hi
maxMemoryMB=64
greeting=null
maxMemoryMB=3422The first run applied a 64 MB heap limit and a system property. The second run, without the variable, used the default limit, which is a fraction of the machine memory (this value depends on the machine) and has no property. The variable is set only for the one command here because it is a prefix assignment. Exporting it affects every JVM the shell starts, including the compiler and the tools in this lesson, which then print the Picked up line too.
| Variable | Read by | Notice printed |
|---|---|---|
JAVA_TOOL_OPTIONS |
Every JVM start, including javac, jcmd, and jshell |
Yes |
JDK_JAVA_OPTIONS |
The java launcher only |
Yes, prefixed with NOTE: |
_JAVA_OPTIONS |
HotSpot JVMs, applied after JAVA_TOOL_OPTIONS (not an official option) |
Yes |
When the same option appears in several places, the command line wins over JAVA_TOOL_OPTIONS for most flags. A value set by the variable is visible with java -XX:+PrintFlagsFinal -version, where the origin column reads command line:
JAVA_TOOL_OPTIONS="-Xmx64m" java -XX:+PrintFlagsFinal -version 2>&1 | grep -E 'Picked|MaxHeapSize'Picked up JAVA_TOOL_OPTIONS: -Xmx64m
size_t MaxHeapSize = 67108864 {product} {command line}
size_t SoftMaxHeapSize = 67108864 {manageable} {ergonomic}The origin {command line} shows that the JVM treats options from this variable as if they had been typed on the command line.
Interview points
java -versionwrites to standard error andjava --versionto standard output;JAVA_HOMEandPATHdecide which JDK answers.java Hello.javacompiles one file in memory and runs it; programs with several source files needjavac.javac -d outwrites class files into a directory tree that mirrors the package names, andjava -cp out pkg.Mainruns the class by its qualified name.jar --create --main-class X -C dir .builds a runnable jar; without-Cthe entries get a wrong prefix andjava -jarfails.jps -l,jcmdwithout arguments, andjstatwork for processes of the same operating system user; a different user or a separate/tmphides the JVM.jcmd <pid> helplists the diagnostic commands of that exact JVM;Thread.print,GC.heap_info,VM.flags,GC.class_histogram, andJFR.startcover most investigations.- A hang is diagnosed with two or three
jstackdumps a few seconds apart; theFound one Java-level deadlocksection names the threads and locks. jmap -histo:liveforces a full collection and pauses the application; the plain histogram does not, but counts unreachable objects too.jstat -gcutil <pid> 1000shows collection counts and times as they change; a risingFGCwith little memory freed points to an undersized heap or a leak.- JFR records with low overhead from inside the JVM;
jfr summaryshows what a file contains andjfr print --eventsextracts one event type. JAVA_TOOL_OPTIONSadds options to every JVM start, prints aPicked upline on standard error, and also affects tools such asjavacandjcmd.
Summary
java --versionprints the vendor build, the release, and the VM mode.java File.java argscompiles and runs a single source file without writing class files.javac -d outcreates the package directory tree underout;--release Nfixes the API and language level.jar --create --file app.jar --main-class pkg.Main -C out .produces a jar thatjava -jarstarts.jar --list --file app.jarlists entries, andMETA-INF/MANIFEST.MFis added automatically.jshell -s script.jshruns snippets and/commands from a file; lines such as/exitcontrol the session.jps -lprints process ids and main classes of JVMs owned by the current user.jcmd <pid> <command>runs a diagnostic command in the target JVM;helplists the available ones.jstack <pid>prints all thread stacks, with thread state, name, and top frames per thread.jmap -histo <pid>prints instance counts and bytes per class;[Bmeansbyte[];:liveforces a collection first.jstat -gcprints capacities and usage in KB plus collection counts and times;-gcutilprints percentages and accepts an interval and a count.jcmd <pid> JFR.startwrites a recording file, andjfr summaryandjfr print --eventsread it.JAVA_TOOL_OPTIONSadds JVM options to every JVM start and printsPicked up JAVA_TOOL_OPTIONSon standard error.
