JDK 内置命令行工具


JPS 工具简介

JPS,用于展示 Java 进程信息(列表)。跟操作系统提供的PS工具类似,PS工具用于显示进程状态(Process Status)。

JPS 展示的是当前用户可看见的 Java 进程,如果看不见某些进程可能需要 sudo、su 之类的命令来切换权限。

查看帮助信息:

jps -help

cmd显示

usage: jps [-help]
       jps [-q] [-mlvV] []

Definitions:
    :      [:]

常用参数是小写的 -v,显示传递给 JVM 的启动参数。

jps -v

cmd显示

57332 Jps -Dapplication.home=C:\Program Files\Java\jdk1.8.0_121 -Xms8m
55240  exit -Xms128m -Xmx2032m -XX:ReservedCodeCacheSize=240m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -ea -XX:CICompilerCount=2 -Dsun.io.useCanonPrefixCache=false -Djava.net.preferIPv4Stack=true -Djdk.http.auth.tunneling.disabledSchemes="" -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Djdk.attach.allowAttachSelf=true -Dkotlinx.coroutines.debug=off -Djdk.module.illegalAccess.silent=true -javaagent:C:\Users\Public\.jetbrains\jetbrains-agent-v3.2.1.c46b.ed7=by https://zhile.io -Djb.vmOptionsFile=C:\Users\Lenovo\.IntelliJIdea2019.3\config\idea64.exe.vmoptions -Djava.library.path=D:\IDEA\IntelliJ IDEA 2019.3.4\jbr\\bin;D:\IDEA\IntelliJ IDEA 2019.3.4\jbr\\bin\server -Didea.jre.check=true -Dide.native.launcher=true -Didea.paths.selector=IntelliJIdea2019.3 -XX:ErrorFile=C:\Users\Lenovo\java_error_in_idea_%p.log -XX:HeapDumpPath=C:\Users\Lenovo\java_error_in_idea.hprof
57032 EchoServer -javaagent:D:\IDEA\IntelliJ IDEA 2019.3.4\lib\idea_rt.jar=11824:D:\IDEA\IntelliJ IDEA 2019.3.4\bin -Dfile.encoding=UTF-8
49228 Launcher -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dpreload.project.path=D:/study-demo/netty_study -Dpreload.config.path=C:/Users/Lenovo/.IntelliJIdea2019.3/config/options -Dexternal.project.config=C:\Users\Lenovo\.IntelliJIdea2019.3\system\external_build_system\netty_study.7d1d3d5d -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Djava.net.preferIPv4Stack=true -Dio.netty.initialSeedUniquifier=4512882475130422037 -Dfile.encoding=GBK -Duser.language=zh -Duser.country=CN -Didea.paths.selector=IntelliJIdea2019.3 -Didea.home.path=D:\IDEA\IntelliJ IDEA 2019.3.4 -Didea.config.path=C:\Users\Lenovo/.IntelliJIdea2019.3/config -Didea.plugins.path=C:\Users\Lenovo/.IntelliJIdea2019.3/config/plugins -Djps.log.dir=C:/Users/Lenovo/.IntelliJIdea2019.3/system/log/build-log -Djps.fallback.jdk.home=D:/IDEA/IntelliJ IDEA 2019.3.4/jbr -Djps.fallback.jdk.version=11.0.6 -Dio.netty.noUnsafe=true -Djava.io.tmpdir=C:/Users/Lenovo/.IntelliJIdea2019.3/system/compile-server/netty_s

看看输出的内容,其中最重要的信息是前面的进程 ID(PID)。

其他参数不太常用:

  • -q:只显示进程号。
  • -m:显示传给 main 方法的参数信息
  • -l:显示启动 class 的完整类名,或者启动 jar 的完整路径
  • -V:大写的 V,这个参数有问题,相当于没传一样。官方说的跟 -q 差不多。
  • :部分是远程主机的标识符,需要远程主机启动 jstatd 服务器支持。

可以看到,格式为 [:],不能用 IP,示例:jps -v sample.com:1099

知道 JVM 进程的 PID 之后,就可以使用其他工具来进行诊断了。

jstat 工具简介

jstat 用来监控 JVM 内置的各种统计信息,主要是内存和 GC 相关的信息。

查看 jstat 的帮助信息,大致如下:

jstat -help

cmd显示

Usage: jstat -help|-options
       jstat -

来看看  部分支持哪些选项:

jstat -options

cmd显示

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

简单说明这些选项。

  • -class:类加载(Class loader)信息统计。
  • -compiler:JIT 即时编译器相关的统计信息。
  • -gc:GC 相关的堆内存信息,用法:jstat -gc -h 10 -t 864 1s 20
  • -gccapacity:各个内存池分代空间的容量。
  • -gccause:看上次 GC、本次 GC(如果正在 GC 中)的原因,其他输出和 -gcutil 选项一致。
  • -gcnew:年轻代的统计信息(New = Young = Eden + S0 + S1)。
  • -gcnewcapacity:年轻代空间大小统计。
  • -gcold:老年代和元数据区的行为统计。
  • -gcoldcapacity:old 空间大小统计。
  • -gcmetacapacity:meta 区大小统计。
  • -gcutil:GC 相关区域的使用率(utilization)统计。
  • -printcompilation:打印 JVM 编译统计信息。

实例:

57032为上面的PID

jstat -gcutil -t 57032

-gcutil 选项是统计 GC 相关区域的使用率(utilization),结果如下:

Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
          105.8   37.03  0.00   20.87  86.82  94.40  89.37   1640    9.248     6    0.658    9.907

-t 选项的位置是固定的,不能在前也不能在后。可以看出是用于显示时间戳,即 JVM 启动到现在的秒数。

简单分析一下:

  • Timestamp 列:JVM 启动了 105.8 秒。
  • S0:就是 0 号存活区的百分比使用率。
  • S1:就是 1 号存活区的百分比使用率。0% 很正常,因为 S0 和 S1 随时有一个是空的。
  • E:就是 Eden 区,新生代的百分比使用率。
  • O:就是 Old 区,老年代。百分比使用率。
  • M:就是 Meta 区,元数据区百分比使用率。
  • CCS:压缩 class 空间(Compressed class space)的百分比使用率。
  • YGC(Young GC):年轻代 GC 的次数。1640次。
  • YGCT 年轻代 GC 消耗的总时间。9.248 秒。
  • FGC:FullGC 的次数,可以看到只发生了 6 次。
  • FGCT:FullGC 的总时间,0.658 秒,平均每次 100ms 左右。
  • GCT:所有 GC 加起来消耗的总时间,即 YGCT + FGCT。

可以看到,-gcutil 这个选项出来的信息不太好用,统计的结果是百分比,不太直观。

再看看 -gc 选项,GC 相关的堆内存信息。

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

其中的 1s 占了  这个槽位,表示每 1 秒输出一次信息。

1s 3 的意思是每秒输出 1 次,最多 3 次。

如果只指定刷新周期,不指定  部分,则会一直持续输出。 退出输出按 CTRL+C 即可。

-h 10 的意思是每 10 行输出一次表头。

Timestamp        S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
         1097.8 10752.0 10752.0  0.0    0.0   65536.0  24962.2   175104.0     0.0     4480.0 770.3  384.0   75.9       0    0.000   0      0.000    0.000
         1098.8 10752.0 10752.0  0.0    0.0   65536.0  24962.2   175104.0     0.0     4480.0 770.3  384.0   75.9       0    0.000   0      0.000    0.000
         1099.8 10752.0 10752.0  0.0    0.0   65536.0  24962.2   175104.0     0.0     4480.0 770.3  384.0   75.9       0    0.000   0      0.000    0.000
         1100.8 10752.0 10752.0  0.0    0.0   65536.0  24962.2   175104.0     0.0     4480.0 770.3  384.0   75.9       0    0.000   0      0.000    0.000
         1101.9 10752.0 10752.0  0.0    0.0   65536.0  24962.2   175104.0     0.0     4480.0 770.3  384.0   75.9       0    0.000   0      0.000    0.000
         1102.9 10752.0 10752.0  0.0    0.0   65536.0  24962.2   175104.0     0.0     4480.0 770.3  384.0   75.9       0    0.000   0      0.000    0.000

详细的解读如下:

  • Timestamp 列:JVM 启动了 1102 秒。
  • S0C:0 号存活区的当前容量(capacity),单位 kB。
  • S1C:1 号存活区的当前容量,单位 kB。
  • S0U:0 号存活区的使用量(utilization),单位 kB。
  • S1U:1 号存活区的使用量,单位 kB。
  • EC:Eden 区,新生代的当前容量,单位 kB。
  • EU:Eden 区,新生代的使用量,单位 kB。
  • OC:Old 区,老年代的当前容量,单位 kB。
  • OU:Old 区,老年代的使用量,单位 kB。 (需要关注)
  • MC:元数据区的容量,单位 kB。
  • MU:元数据区的使用量,单位 kB。
  • CCSC:压缩的 class 空间容量,单位 kB。
  • CCSU:压缩的 class 空间使用量,单位 kB。
  • YGC:年轻代 GC 的次数。
  • YGCT:年轻代 GC 消耗的总时间。 (重点关注)
  • FGC:Full GC 的次数
  • FGCT:Full GC 消耗的时间。 (重点关注)
  • GCT:垃圾收集消耗的总时间。

最重要的信息是 GC 的次数和总消耗时间,其次是老年代的使用量。

在没有其他监控工具的情况下, jstat 可以简单查看各个内存池和 GC 的信息,可用于判别是否是 GC 问题或者内存溢出。

jmap 工具

jmap 主要用来 Dump 堆内存。当然也支持输出统计信息。

官方推荐使用 JDK 8 自带的 jcmd 工具来取代 jmap,但是 jmap 深入人心,jcmd 可能暂时取代不了。

查看 jmap 帮助信息:

jmap -help

cmd显示

Usage:
    jmap [option] 
        (to connect to running process)(连接到本地进程)
    jmap [option] 
        (to connect to a core file)(连接到 core file)
    jmap [option] [server_id@]
        (to connect to remote debug server)(连接到远程 debug 服务)

where 

常用选项就 3 个:

  • -heap:打印堆内存(/内存池)的配置和使用信息。
  • -histo:看哪些类占用的空间最多,直方图。
  • -dump:format=b,file=xxxx.hprof:Dump 堆内存。

示例:看堆内存统计信息。

jmap -heap 57032

cmd显示

Attaching to process ID 57032, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.121-b13

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

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 4263510016 (4066.0MB)
   NewSize                  = 89128960 (85.0MB)
   MaxNewSize               = 1420820480 (1355.0MB)
   OldSize                  = 179306496 (171.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 = 67108864 (64.0MB)
   used     = 25561280 (24.37713623046875MB)
   free     = 41547584 (39.62286376953125MB)
   38.08927536010742% used
From Space:
   capacity = 11010048 (10.5MB)
   used     = 0 (0.0MB)
   free     = 11010048 (10.5MB)
   0.0% used
To Space:
   capacity = 11010048 (10.5MB)
   used     = 0 (0.0MB)
   free     = 11010048 (10.5MB)
   0.0% used
PS Old Generation
   capacity = 179306496 (171.0MB)
   used     = 0 (0.0MB)
   free     = 179306496 (171.0MB)
   0.0% used

4676 interned Strings occupying 380808 bytes.
  • Attached,连着;
  • Detached,分离。

可以看到堆内存和内存池的相关信息。当然,这些信息有多种方式可以得到,比如 JMX。

看看直方图:

jmap -histo 57032

 cmd显示

 num     #instances         #bytes  class name
----------------------------------------------
   1:         16446       10676728  [B
   2:          3402        5836648  [I
   3:         46729        5208072  [C
   4:         27444         658656  java.lang.String
   5:          3591         481880  [Ljava.lang.Object;
   6:          6169         246032  [S
   7:          1701         191624  java.lang.Class

简单分析,其中 [C 占用了 5MB 内存。

[C 表示 chat[][B 表示 byte[][I 表示 int[],其他类似。这种基础数据类型很难分析出什么问题。

Java 中的大对象、巨无霸对象,一般都是长度很大的数组。

Dump 堆内存:

jmap -dump:format=b,file=57032.hprof 57032

 cmd显示

Dumping heap to C:\Users\Lenovo\57032.hprof ...
Heap dump file created

导出完成后,dump 文件大约和堆内存一样大。可以想办法压缩并传输。

分析 hprof 文件可以使用 jhat 或者 mat 工具。

jcmd 工具

诊断工具:jcmd 是 JDK 8 推出的一款本地诊断工具,只支持连接本机上同一个用户空间下的 JVM 进程。

查看帮助:

jcmd -help
Usage: jcmd class> 
   or: jcmd -l
   or: jcmd -h

  command must be a valid jcmd command for the selected jvm.//command 必须是指定 JVM 可用的有效 jcmd 命令。
  Use the command "help" to see which commands are available.//可以使用 "help" 命令查看该 JVM 支持哪些命令。  
  If the pid is 0, commands will be sent to all Java processes.//如果指定 pid 部分的值为 0,则会将 commands 发送给所有可见的 Java 进程。  
  The main class argument will be used to match (either partially //指定 main class 则用来匹配启动类。可以部分匹配。(适用同一个类启动多实例)。   
  or fully) the class used to start Java.
  If no options are given, lists Java processes (same as -p).

  PerfCounter.print display the counters exposed by this process //命令可以展示该进程暴露的各种计数器
  -f  read and execute commands from the file //从文件读取可执行命令          
  -l  list JVM processes on the local machine //列出(list)本机上可见的 JVM 进程            
  -h  this help

查看进程信息:

jcmd
jcmd -l
jps -lm
14596 com.fhj.jvm.JvmTest

这几个命令的结果差不多。可以看到其中有一个 PID 为 14596 的进程,下面看看可以用这个 PID 做什么。

给这个进程发一个 help 指令:

jcmd 14596 help
jcmd JvmTest help

pid 和 main-class 输出信息是一样的:

14596:
The following commands are available:
JFR.stop
JFR.start
JFR.dump
JFR.check
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
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

可以试试这些命令。查看 VM 相关的信息:

# JVM 实例运行时间
jcmd 14596 VM.uptime
14596:
133.763 s

#JVM 版本号
jcmd 14596 VM.version
14596:
Java HotSpot(TM) 64-Bit Server VM version 25.66-b18
JDK 8.0_66

# JVM 实际生效的配置参数
jcmd 14596 VM.flags
14596:
-XX:CICompilerCount=3 -XX:InitialHeapSize=8388608 -XX:MaxHeapSize=8388608 -XX:MaxNewSize=2621440 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=2621440 -XX:OldSize=5767168 -XX:+PrintGC -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

# 查看命令行参数
jcmd 14596 VM.command_line
14596:
VM Arguments:
jvm_args: -Xmx8m -XX:+PrintGC -Dfile.encoding=UTF-8
java_command: com.fhj.jvm.JvmTest
java_class_path (initial): ...(xxx省略)...
Launcher Type: SUN_STANDARD

# 系统属性
jcmd 14596 VM.system_properties
14596
...
java.runtime.name=Java(TM) SE Runtime Environment
java.vm.version=25.66-b18
java.vm.vendor=Oracle Corporation
user.country=CN
...

GC 相关的命令,统计每个类的实例占用字节数。

jcmd 14596 GC.class_histogram
14596:

 num     #instances         #bytes  class name
----------------------------------------------
   1:          1161         895656  [B
   2:          4847         473176  [C
   3:          4687         112488  java.lang.String
   4:           701          79992  java.lang.Class
   5:           655          46880  [Ljava.lang.Object;
   6:           841          33640  java.util.TreeMap$Entry
   7:           537          17184  java.util.HashMap$Node
   8:           265          12424  [Ljava.lang.String;
   9:           734          11744  com.fhj.jvm.JvmTest
  10:           137           8768  java.net.URL
  11:           135           7680  [I

Dump 堆内存:

jcmd 11155 help GC.heap_dump
14596:
GC.heap_dump
Generate a HPROF format dump of the Java heap.

Impact: High: Depends on Java heap size and content. Request a full GC unless the '-all' option is specified.

Permission: java.lang.management.ManagementPermission(monitor)

Syntax : GC.heap_dump [options] 

Arguments:
        filename :  Name of the dump file (STRING, no default value)

Options: (options must be specified using the  or = syntax)
        -all : [optional] Dump all objects, including unreachable objects (BOOLEAN, false)

jcmd 和jmap 两者效果差不多; jcmd 需要指定绝对路径; jmap 不能指定绝对路径

jcmd 14596 GC.heap_dump -all=true d:/14596-by-jcmd.hprof
jmap -dump:file=./14596-by-jmap.hprof 14596

jcmd 坑的地方在于,必须指定绝对路径,否则导出的 hprof 文件就以 JVM 所在的目录计算。(因为是发命令交给 JVM 执行的)

jstack 工具

命令行工具、诊断工具:jstack 工具可以打印出 Java 线程的调用栈信息(Stack Trace)。一般用来查看存在哪些线程,诊断是否存在死锁等。

看看帮助信息:

jstack -help
Usage:
    jstack [-l] 
        (to connect to running process)
    jstack -F [-m] [-l] 
        (to connect to a hung process)
    jstack [-m] [-l]  
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]
        (to connect to a remote debug server)

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

选项说明:

  • -F:强制执行 Thread Dump,可在 Java 进程卡死(hung 住)时使用,此选项可能需要系统权限。
  • -m:混合模式(mixed mode),将 Java 帧和 native 帧一起输出,此选项可能需要系统权限。
  • -l:长列表模式,将线程相关的 locks 信息一起输出,比如持有的锁,等待的锁。

常用的选项是 -l,示例用法。

jstack 4524
jstack -l 4524

cmd显示

Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.66-b18 mixed mode):

"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000014a88800 nid=0x2b50 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C1 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x0000000014a13000 nid=0x1c14 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x0000000014a11000 nid=0x72e8 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x00000000149e4800 nid=0x7a30 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x00000000149a3000 nid=0x5488 runnable [0x0000000014f0e000]
   java.lang.Thread.State: RUNNABLE
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:170)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
        - locked <0x00000000ff97bc10> (a java.io.InputStreamReader)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at java.io.BufferedReader.fill(BufferedReader.java:161)
        at java.io.BufferedReader.readLine(BufferedReader.java:324)
        - locked <0x00000000ff97bc10> (a java.io.InputStreamReader)
        at java.io.BufferedReader.readLine(BufferedReader.java:389)
        at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:61)

   Locked ownable synchronizers:
        - None

"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000012e20800 nid=0x7018 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000012e2e800 nid=0x5fe4 runnable [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
        - None

"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000002a49800 nid=0x6abc in Object.wait() [0x000000001478f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000ff9506a0> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x00000000ff9506a0> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

   Locked ownable synchronizers:
        - None

"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000002a43000 nid=0x1f14 in Object.wait() [0x000000001468f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x00000000ff975d60> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)
        - locked <0x00000000ff975d60> (a java.lang.ref.Reference$Lock)

   Locked ownable synchronizers:
        - None

"main" #1 prio=5 os_prio=0 tid=0x0000000002952800 nid=0x3374 waiting on condition [0x00000000024af000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at com.fhj.jvm.JvmTest.main(JvmTest.java:13)

   Locked ownable synchronizers:
        - None

"VM Thread" os_prio=2 tid=0x0000000012dd8000 nid=0x7b08 runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002968800 nid=0x4140 runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x000000000296a000 nid=0x37a8 runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000296b800 nid=0x682c runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000296d000 nid=0x2798 runnable

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x000000000296f800 nid=0x6c48 runnable

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000000002970800 nid=0x6914 runnable

"VM Periodic Task Thread" os_prio=2 tid=0x0000000014ac5000 nid=0x67c waiting on condition

JNI global references: 17

死锁的原因一般是锁定多个资源的顺序出了问题(交叉依赖)。

jinfo 工具

诊断工具:jinfo 用来查看具体生效的配置信息以及系统属性,还支持动态增加一部分参数。

看看帮助信息:

jinfo -help
Usage:
    jinfo [option] 
        (to connect to running process)
    jinfo [option] 
        (to connect to a core file)
    jinfo [option] [server_id@]
        (to connect to remote debug server)

where 

使用示例:

jinfo 1556
jinfo -flags 1556

不加参数过滤,则打印所有信息。

Attaching to process ID 1556, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.66-b18
Java System Properties:

java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.66-b18
sun.boot.library.path = D:\Java\jdk1.8.0_66\jre\bin
java.vendor.url = http://java.oracle.com/
。。。。。。
java.ext.dirs = D:\Java\jdk1.8.0_66\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
sun.boot.class.path = D:\Java\jdk1.8.0_66\jre\lib\resources.jar;D:\Java\jdk1.8.0_66\jre\lib\rt.jar;D:\Java\jdk1.8.0_66\jre\lib\sunrsasign.jar;D:\Java\jdk1.8.0_66\jre\lib\jsse.jar;D:\Java\jdk1.8.0_66\jre\lib\jce.jar;D:\Java\jdk1.8.0_66\jre\lib\charsets.jar;D:\Java\jdk1.8.0_66\jre\lib\jfr.jar;D:\Java\jdk1.8.0_66\jre\classes
java.vendor = Oracle Corporation
file.separator = \
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64

VM Flags:
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=8388608 -XX:MaxHeapSize=8388608 -XX:MaxNewSize=2621440 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=2621440 -XX:OldSize=5767168 -XX:+PrintGC -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:  -Xmx8m -XX:+PrintGC -Dfile.encoding=UTF-8

可以看到所有的系统属性和启动使用的 VM 参数、命令行参数。非常有利于我们排查问题,特别是去排查一个已经运行的 JVM 里问题,通过 jinfo 我们就知道它依赖了哪些库,用了哪些参数启动。

jrunscript 和 jjs 工具

jrunscript 和 jjs 工具用来执行脚本,只要安装了 JDK 8+,就可以像 shell 命令一样执行相关的操作了。这两个工具背后,都是 JDK 8 自带的 JavaScript 引擎 Nashorn。

执行交互式操作:

jrunscript
nashorn> 66+88
154

或者:

jjs
jjs> 66+88
154

按 CTRL+C 或者输入 exit() 回车,退出交互式命令行。

其中 jrunscript 可以直接用来执行 JS 代码块或 JS 文件。比如类似 curl 这样的操作:

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

或者这样:

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

甚至可以执行 JS 脚本:

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

而 jjs 则只能交互模式,但是可以指定 JavaScript 支持的 ECMAScript 语言版本,比如 ES5 或者 ES6。

这个工具在某些情况下还是有用的,还可以在脚本中执行 Java 代码,或者调用用户自己的 jar 文件或者 Java 类。

如果是 JDK 9 及以上的版本,则有一个更完善的 REPL 工具——JShell,可以直接解释执行 Java 代码。

JVM