09 Jdk Built in Command Line Tools to Perfect One's Work, Tools Must First Be Honed

09 JDK Built-in Command-Line Tools- To Perfect One’s Work, Tools Must First Be Honed #

In many cases, there may not be handy tools in the JVM runtime environment, so it is essential to master the basic built-in tools.

The tools and programs that come with JDK can be divided into two main types:

  1. Development tools
  2. Diagnostic analysis tools

JDK Built-in Development Tools #

Students who have written Java programs should be familiar with the development tools in JDK. The following are some commonly used ones:

Tool Description
java The startup program for Java applications
javac The built-in compiler tool in JDK
javap The tool for decompiling class files
javadoc Automatically generates related API documentation based on Java code and standard annotations
javah Generates the necessary .h files based on Java code when developing with JNI
extcheck Checks whether there is any version conflict between a jar file and the runtime extension jar, rarely used
jdb Java Debugger, which can debug local and remote programs, is a demo implementation of JPDA for other debuggers to refer to. Rarely used during development
jdeps Detects the dependencies required by class or jar files
jar Packaging tool that packages files and directories into .jar files; .jar files are essentially zip files with a different suffix. When using, match the options and parameters in the correct order.
keytool A management tool for security certificates and keys (supports operations such as generation, import, and export)
jarsigner A tool for signing and verifying jar files
policytool Actually, this is a graphical tool for managing Java security policies on the local machine

Development tools will not be described in detail here. Interested students can refer to the links at the end of the article.

Now let’s introduce the diagnostic and analysis tools.

Command-line Diagnostic and Analysis Tools #

JDK provides various command-line tools, which can be used to quickly view the basic information of JVM instances when conditions are limited.

On macOS X and Windows systems, some tools may fail or give errors due to insufficient account permissions. If there are any issues, please consider this factor.

Introduction to the JPS Tool #

As we know, the operating system provides a tool called ps, which is used to display the status of processes (Process Status).

Java also provides a similar command-line tool called JPS, which is used to display information or a list of Java processes.

It is important to note that JPS displays Java processes that are visible to the current user. If certain processes are not visible, sudo or su commands may be required to switch permissions.

To view the help information:

$ jps -help

usage: jps [-help]
       jps [-q] [-mlvV] [<hostid>]
Definitions:
    <hostid>:      <hostname>[:<port>]

As you can see, these parameters are divided into multiple groups, -help, -q, -mlvV. Parameters within the same group can share a single -.

The commonly used parameter is the lowercase -v, which displays the startup arguments passed to the JVM.

$ jps -v

15883 Jps -Dapplication.home=/usr/local/jdk1.8.0_74 -Xms8m
6446 Jstatd -Dapplication.home=/usr/local/jdk1.8.0_74 -Xms8m
        -Djava.security.policy=/etc/java/jstatd.all.policy
32383 Bootstrap -Xmx4096m -XX:+UseG1GC -verbose:gc
        -XX:+PrintGCDateStamps -XX:+PrintGCDetails
        -Xloggc:/xxx-tomcat/logs/gc.log
        -Dcatalina.base=/xxx-tomcat -Dcatalina.home=/data/tomcat

Take a look at the output, and the most important information is the PID (Process ID) at the beginning.

Other parameters are not commonly used:

  • -q: Only displays the process ID.
  • -m: Displays the arguments passed to the main method.
  • -l: Displays the full class name for the startup class or the full path for the startup jar.
  • -V: Uppercase V, this parameter has issues and is similar to not passing any parameter. According to official documentation, it is similar to -q.
  • <hostid>: Partially identifies the remote host and requires the jstatd server support to be started on the remote host.

As you can see, the format is <hostname>[:<port>], and IP cannot be used. For example: jps -v sample.com:1099. Once you know the PID of the JVM process, you can use other tools for diagnosis.

Introduction to jstat tool #

jstat is used to monitor various statistics in the JVM, mainly memory and GC-related information.

To view the help information for jstat, it looks something like this:

$ jstat -help

Usage: jstat -help|-options
       jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

Definitions:
  <option>      available options, see below
  <vmid>        virtual machine identifier, format: <lvmid>[@<hostname>[:<port>]]
  <lines>       interval between header lines.
  <interval>    sampling interval. <n>["ms"|"s"], default unit is ms
  <count>       number of samples to take
  -J<flag>      pass <flag> directly to the underlying JVM

Let’s take a look at the <option> section to see which options are supported:

$ jstat -options

-class
-compiler
-gc
-gccapacity
-gccause
-gcmetacapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcutil
-printcompilation

Here is a brief explanation of these options, feel free to skip if not interested.

  • -class: Statistics on class loading.
  • -compiler: Statistics related to the JIT (Just-In-Time) compiler.
  • -gc: GC-related heap memory information. Usage: jstat -gc -h 10 -t 864 1s 20.
  • -gccapacity: Capacity of various memory pools in generations.
  • -gccause: Cause of the last GC and current GC (if in progress). Other outputs are consistent with the -gcutil option.
  • -gcnew: Statistics on the young generation (New = Young = Eden + S0 + S1).
  • -gcnewcapacity: Statistics on the young generation space size.
  • -gcold: Behavior statistics for the old generation and metaspace.
  • -gcoldcapacity: Statistics on the old generation space size.
  • -gcmetacapacity: Statistics on the metaspace size.
  • -gcutil: Utilization statistics of GC-related areas.
  • -printcompilation: Print JVM compilation statistics.

Example:

jstat -gcutil -t 864

The -gcutil option is used to measure the utilization of GC-related areas. The result looks like this:

Timestamp S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
14251645.5 0.00 13.50 55.05 71.91 83.84 69.52 113767 206.036 4 0.122 206.158

The position of the -t option is fixed and cannot be placed before or after. It is used to display the timestamp, which is the number of seconds since JVM startup.

A simple analysis:

  • Timestamp column: The JVM has been running for about 14.25 million seconds, approximately 164 days.
  • S0: The percentage utilization of survivor space 0. 0% is normal because either S0 or S1 is always empty.
  • S1: The percentage utilization of survivor space 1.
  • E: The percentage utilization of the Eden space in the young generation.
  • O: The percentage utilization of the old generation.
  • M: The percentage utilization of the metaspace.
  • CCS: The percentage utilization of the compressed class space.
  • YGC (Young GC): The number of young generation GCs. More than 110,000 times, which is not a small number.
  • YGCT: The total time consumed by young generation GC. 206 seconds, less than one ten-thousandth of the total runtime, basically negligible.
  • FGC: The number of Full GCs. Only 4 times, so there shouldn’t be any major issues.
  • FGCT: The total time consumed by Full GC. 0.122 seconds, averaging around 30 ms per occurrence, which most systems should be able to handle.
  • GCT: The total time consumed by all GCs, which is the sum of YGCT and FGCT.

As you can see, the information provided by the -gcutil option is not very useful, as it gives the results in percentages, which are not very intuitive.

Let’s take a look at the -gc option, which provides GC-related heap memory information.

jstat -gc -t 864 1s
jstat -gc -t 864 1s 3
jstat -gc -t -h 10 864 1s 15

In the above commands, 1s is occupying the <interval> slot, indicating that the information will be outputted every 1 second.

The meaning of 1s 3 is that the information will be outputted once every second, for a maximum of 3 times.

If only the refresh interval is specified and the <count> part is not, the output will continue indefinitely. To exit the output, press CTRL+C.

The meaning of -h 10 is to output the table header every 10 lines.

The results are roughly as follows:

Timestamp S0C S1C S0U S1U EC EU OC OU MC MU YGC YGCT FGC FGCT
14254245.3 1152.0 1152.0 145.6 0.0 9600.0 2312.8 11848.0 8527.3 31616.0 26528.6 113788 206.082 4 0.122
14254246.3 1152.0 1152.0 145.6 0.0 9600.0 2313.1 11848.0 8527.3 31616.0 26528.6 113788 206.082 4 0.122
14254247.3 1152.0 1152.0 145.6 0.0 9600.0 2313.4 11848.0 8527.3 31616.0 26528.6 113788 206.082 4 0.122

The above results have been simplified for formatting purposes, omitting the GCT, CCSC, and CCSU columns. By looking at these words, you can try to guess their meanings. Here is a detailed interpretation:

  • Timestamp column: The JVM has been running for 14.25 million seconds, approximately 164 days.
  • S0C: The current capacity of survivor space 0, in kilobytes.
  • S1C: The current capacity of survivor space 1, in kilobytes.
  • S0U: The usage of survivor space 0, in kilobytes.
  • S1U: The usage of survivor space 1, in kilobytes.
  • EC: The current capacity of Eden space, in kilobytes.
  • EU: The usage of Eden space, in kilobytes.
  • OC: The current capacity of the old generation space, in kilobytes.
  • OU: The usage of the old generation space, in kilobytes. (This is the most important to monitor)
  • MC: The capacity of the metaspace, in kilobytes.
  • MU: The usage of the metaspace, in kilobytes.
  • CCSC: The compressed class space capacity, in kilobytes.
  • CCSU: The compressed class space usage, in kilobytes.
  • YGC: The number of young generation GCs.
  • YGCT: The total time spent in young generation GCs. (Important to monitor)
  • FGC: The number of full GCs.
  • FGCT: The total time spent in full GCs. (Important to monitor)
  • GCT: The total time spent in garbage collection.

The most important information is the number and total time of GCs, followed by the usage of the old generation.

In the absence of other monitoring tools, jstat can be used to quickly check various memory pools and GC information, which can help determine whether there are GC issues or memory leaks.

jmap Tool #

The most commonly asked about tool in interviews is the jmap tool. jmap is mainly used to dump the heap memory. It also supports outputting statistical information.

Although the official recommendation is to use the jcmd tool that comes with JDK 8 instead of jmap, jmap is still widely used and may not be replaced by jcmd temporarily.

To view the help information for jmap, use the following command:

$ jmap -help

Usage:
    jmap [option] <pid>
        (to connect to running process)
    jmap [option] <executable <core>
        (to connect to a core file)
    jmap [option] [server_id@]<remote-IP-or-hostname>
        (to connect to remote debug server)

where <option> is one of:
    <none>               to print same info as Solaris pmap
    -heap                to print java heap summary
    -histo[:live]        to print histogram of java object heap; if the "live" suboption is specified, only count live objects
                         (same as jmap -histo if VM not started with -Xbatch)
    -clstats             to print class loader statistics
    -finalizerinfo       to print information on objects awaiting finalization
    -dump:<dump-options> to dump java heap in hprof binary format
                         dump-options:
                           live         dump only live objects; if not specified, all objects are dumped
                           format=b     binary format
                           file=<file>  dump heap to <file>
                     use the "jmap -help" command to see all available options and for further details.
                     (same as jmap -h)
    -F               Force export. Use this option if jmap hangs and does not respond, and disconnect and use this option later.
                      The "live" option does not support force export.
    -h | -help       To print this help message
    -J<flag>         To pass <flag> directly to the runtime system

There are only 3 common options:

  • -heap: Print configuration and usage information of the heap memory (/memory pool).
  • -histo: See which classes occupy the most space, histogram.
  • -dump:format=b,file=xxxx.hprof: Dump heap memory.

Example: View heap memory statistics.

$ jmap -heap 4524

Output:

Attaching to process ID 4524, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.65-b01

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 2069889024 (1974.0MB)
   NewSize                  = 42991616 (41.0MB)
   MaxNewSize               = 689963008 (658.0MB)
   OldSize                  = 87031808 (83.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 24117248 (23.0MB)
   used     = 11005760 (10.49591064453125MB)
   free     = 13111488 (12.50408935546875MB)
   45.63439410665761% used
From Space:
   capacity = 1048576 (1.0MB)
   used     = 65536 (0.0625MB)
   free     = 983040 (0.9375MB)
   6.25% used
To Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
PS Old Generation
   capacity = 87031808 (83.0MB)
   used     = 22912000 (21.8505859375MB)
   free     = 64119808 (61.1494140625MB)
   26.32600715361446% used

12800 interned Strings occupying 1800664 bytes.
  • Attached
  • Detached

You can see the relevant information about the heap memory and memory pool. Of course, there are multiple ways to obtain this information, such as JMX.

Let’s take a look at the histogram:

$ jmap -histo 4524

The result is:

 num     #instances         #bytes  class name
----------------------------------------------
   1:         52214       11236072  [C
   2:        126872        5074880  java.util.TreeMap$Entry
   3:          5102        5041568  [B
   4:         17354        2310576  [I
   5:         45258        1086192  java.lang.String
......

Simple analysis shows that [C occupies 11MB of memory and does not take up much space.

[C represents char[], [B represents byte[], [I represents int[], and so on. It is difficult to analyze problems with these basic data types.

In Java, large objects or gigantic objects are usually arrays with a large length.

Dump heap memory:

cd $CATALINA_BASE
jmap -dump:format=b,file=3826.hprof 3826

After the export is complete, the dump file is about the same size as the heap memory. You can compress and transfer it.

The hprof file can be analyzed using the jhat or mat tool.

jcmd tool #

Diagnostic tool: jcmd is a native diagnostic tool introduced in JDK 8, which only supports connecting to JVM processes in the same user space on the local machine.

View help:

$ jcmd -help

Usage: jcmd <pid | main class> <command ...|PerfCounter.print|-f file>
   or: jcmd -l                                                   
   or: jcmd -h                                                   

  Commands:
    <command>
        This must be an available command for the target JVM. 
        Use 'help' command to see what commands are available on remote JVM.
    -f 
        Take commands from the file. 
        Use '-' filename to read commands from standard input.
    -l
        List Java process that are currently running.
    -h or -help to print this help message.

View process information:

jcmd
jcmd -l
jps -lm

The results of these commands are almost the same. You can see that there is a process with a PID of 11155. Let’s see what we can do with this PID.

Send a help command to this process:

jcmd 11155 help
jcmd RemoteMavenServer help

The output information of pid and main class is the same:

11155:
The following commands are available:
VM.native_memory
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.run_finalization
GC.run
VM.uptime
VM.flags
VM.system_properties
VM.command_line
VM.version
help

You can try these commands. View VM-related information:

# JVM running time
jcmd 11155 VM.uptime
9307.052 s

# JVM version
jcmd 11155 VM.version
OpenJDK 64-Bit Server VM version 25.76-b162
JDK 8.0_76

# JVM effective configuration parameters
jcmd 11155 VM.flags
11155:
-XX:CICompilerCount=4 -XX:InitialHeapSize=268435456
-XX:MaxHeapSize=536870912 -XX:MaxNewSize=178782208
-XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960
-XX:OldSize=179306496 -XX:+UseCompressedClassPointers
-XX:+UseCompressedOops -XX:+UseParallelGC

# View command line parameters
jcmd 11155 VM.command_line
VM Arguments:
jvm_args: -Xmx512m -Dfile.encoding=UTF-8
java_command: org.jetbrains.idea.maven.server.RemoteMavenServer
java_class_path (initial): ...(omitted)...
Launcher Type: SUN_STANDARD

# System properties
jcmd 11155 VM.system_properties
...
java.runtime.name=OpenJDK Runtime Environment
java.vm.version=25.76-b162
java.vm.vendor=Oracle Corporation
user.country=CN

GC-related commands, statistics of the number of bytes occupied by each instance of each class.

$ jcmd 11155 GC.class_histogram

 num     #instances         #bytes  class name
----------------------------------------------
   1:         11613        1420944  [C
   2:          3224         356840  java.lang.Class
   3:           797         300360  [B
   4:         11555         277320  java.lang.String
   5:          1551         193872  [I
   6:          2252         149424  [Ljava.lang.Object;

Dump heap memory:

$jcmd 11155 help GC.heap_dump

Syntax : GC.heap_dump [options] <filename>
Arguments: filename :  Name of the dump file (STRING, no default value)
Options:  -all=true or -all=false (default)
jcmd 11155 GC.heap_dump -all=true ~/11155-by-jcmd.hprof
jmap -dump:file=./11155-by-jmap.hprof 11155

The pit of jcmd is that you must specify the absolute path, otherwise the exported hprof file will be calculated relative to the JVM directory (because the command is sent to the JVM for execution).

The usage of other commands is similar. Please refer to the official documentation as needed.

jstack tool #

Command line tool, diagnostic tool: jstack can print the call stack information of Java threads (Stack Trace). It is generally used to see which threads exist and diagnose whether there are deadlocks, etc.

At this time, you can see the importance of naming threads or thread pools (if the development is not standardized, the entire project will be a pit). You can refer to Alibaba’s Java development specifications for details.

View the help information:

$jstack -help

Usage: jstack [-l] <pid>
Options:
    -l  Long listing. Prints additional information about locks
        -pid 方式使用进程编号
        -f filename  导出结果到文件中
        -h to print help message
    jstack [-l] <pid>
        (to connect to a running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  print both Java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help prints this help message

Explanation of options:

  • -F: Forces a thread dump. Use this option when a Java process is hung. This option may require system privileges.
  • -m: Mixed mode. Prints both Java frames and native frames. This option may require system privileges.
  • -l: Long listing mode. Prints additional information about locks, such as held locks and waiting locks.

The commonly used option is -l. Here are some usage examples:

jstack 4524
jstack -l 4524

The most common cause of a deadlock is an incorrect ordering of locking multiple resources (interdependency). There are many examples of such code online. You can search for “Java deadlock example”.

On Linux and macOS, the effect of jstack pid is the same as kill -3 pid.

jinfo Tool #

The diagnostic tool jinfo can be used to view the specific configuration information and system properties that are in effect. It also supports dynamically adding some parameters.

Let’s take a look at the help information:

$ jinfo -help

Usage:
    jinfo [option] <pid>
        (to connect to a running process)
    jinfo [option] <executable> <core>
        (to connect to a core file)
    jinfo [option] [server_id@]<remote-IP-hostname>
        (to connect to a remote debug server)

where <option> is one of:
    -flag <name>         to print the value of the named VM flag
    -flag [+|-]<name>    to enable or disable the named VM flag
    -flag <name>=<value> to set the named VM flag to the given value
    -flags               to print VM flags
    -sysprops            to print Java system properties
    <no option>          to print both of the above
    -h | -help           to print this help message

Usage examples:

jinfo 36663
jinfo -flags 36663

If no filtering parameter is provided, all information will be printed.

jinfo is more stable on Windows. On macOS, it requires root privileges or the current user’s password to be entered when prompted.

56345767.png

You will then see the following information:

jinfo 36663
Attaching to process ID 36663, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
Java System Properties:

java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.131-b11
sun.boot.library.path = /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib
// Several lines omitted
java.ext.dirs = /Users/kimmking/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
sun.boot.class.path = /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/classes
java.vendor = Oracle Corporation
maven.home = /Users/kimmking/tools/apache-maven-3.5.0
file.separator = /
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeBig
sun.cpu.endian = little
sun.cpu.isalist =

VM Flags:
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=2147483648 -XX:MaxNewSize=715653120 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=44564480 -XX:OldSize=89653248 -XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC
Command line: -Dclassworlds.conf=/Users/kimmking/tools/apache-maven-3.5.0/bin/m2.conf -Dmaven.home=/Users/kimmking/tools/apache-maven-3.5.0 -Dmaven.multiModuleProjectDirectory=/Users/kimmking/gateway/spring-cloud-gateway-demo/netty-server

You can see all the system properties, VM arguments, and command line parameters used for startup. This is very useful for troubleshooting, especially when investigating issues within a running JVM. With jinfo, we can determine the libraries it depends on and the arguments used for startup.

If you are encountering constant errors when using jinfo on a Mac or Linux system, it may be due to lack of permissions or a version mismatch between jinfo and the target JVM. For example:

Error attaching to process:
  sun.jvm.hotspot.runtime.VMVersionMismatchException:
    Supported versions are 25.74-b02. Target VM is 25.66-b17

jrunscript and jjs Tools #

The jrunscript and jjs tools are used to execute scripts. As long as JDK 8+ is installed, you can perform operations similar to shell commands using these tools. Both of these tools are based on the Nashorn JavaScript engine, which is included in JDK 8.

To perform interactive operations:

$ jrunscript
nashorn> 66+88
154

or:

$ jjs
jjs> 66+88
154

Pressing CTRL+C or entering exit() and pressing Enter will exit the interactive command line.

jrunscript can be used to execute JavaScript code blocks or JavaScript files. For example, an operation similar to curl:

jrunscript -e "cat('http://www.baidu.com')"

or:

jrunscript -e "print('hello,kk.jvm'+1)"

You can even execute JavaScript scripts:

jrunscript -l js -f /XXX/XXX/test.js

On the other hand, jjs only supports interactive mode but allows you to specify the ECMAScript language version, such as ES5 or ES6.

This tool can be useful in certain situations, as it allows you to execute Java code or call your own jar files or Java classes within the script. You can refer to the following documentation for detailed instructions:

For JDK 9 and above, there is a more comprehensive REPL tool called JShell, which can directly interpret and execute Java code.

Please note that these performance diagnostic tools are not officially supported, so if you encounter error messages, don’t worry and try other tools. If necessary, you can also try a different JDK version.

Reference Documentation #