JDK Tools简介

图片来自pixabay.com的StockSnap-894430会员

1. 简介

Oracle JDK在发布的SDK包中,除了核心类库、编译、运行和调试工具,还带了大量的监视查看工具。这些监视工具可以辅助开发者查看Java程序的运行状态,包括环境配置、内存、CPU、线程、堆栈、类加载等各种信息。本文将对这些监视工具进行介绍。

本文的工具介绍将主要参考JDK 8的官方文档,并以jdk 8为运行环境演示命令输出。

2. 官方文档

  1. JDK 10 tools
  2. JDK 9 tools
  3. JDK 8 tools
  4. JDK 5 tools

2. 各个工具简介

2.1 基本工具

  1. java 启动java应用程序命令
  2. javac 编译工具,将java源代码编译为java bytecode文件
  3. jar 打包归档工具,也可以对包进行解压
  4. javadoc 生成java api说明和使用文档工具

    基本工具的使用方法可参考这篇文章

2.1 常用的监控分析工具

  1. jps 查看java进程状态工具
  2. jstat 内存监视工具
  3. jmap 内存查看工具,获取内存快照
  4. jinfo 获取java进程的环境配置信息
  5. jstack 进程中各个线程的调用栈查看工具
  6. jconsole 一个java进程的监视和管理控制台,可以查看进程的CPU、内存、线程运行情况,还可以辅助检测死锁,查看类加载详细情况
  7. jvisualvm.exe 一个可视化的java进程管理工具,可以查看进程的CPU、内存、线程运行情况。

    上述监控分析工具的使用方法见下文。

3. 工具使用方法

3.1 jps

  • 简单的命令,输出进程id:jps
  • 输出进程的id,main程序全package路径名,启动参数:jps -mlvV
  • 还可以配合jstat server/RMI registry,实现查看远程服务器上的java进程列表:jps -l remote.domain

一个命令输出样例如下,

$ jps -mlvV
16552 jdk.jcmd/sun.tools.jps.Jps -mlvV -Dapplication.home=G:\local\java\jdk-9.0.1 -Xms8m -Djdk.module.main=jdk.jcmd

3.2 jstat

检查进程15644的内存使用(garbage collected heap)情况

$ jstat -gc 17152
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
10752.0 10752.0  0.0    0.0   64512.0   2580.5   172032.0     0.0     4480.0 770.2  384.0   75.9       0    0.000   0      0.000    0.000

每隔5秒检查进程15644的内存使用情况,输出中添加timestamp,每隔5行添加header,

$ jstat -gcutil -t -h5 15644 500
Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
         2926.3   0.00  89.58  32.70   1.42  94.99  90.00      7    0.025     1    0.012    0.037
         2926.8   0.00  89.58  33.13   1.42  94.99  90.00      7    0.025     1    0.012    0.037
         2927.3   0.00  89.58  33.13   1.42  94.99  90.00      7    0.025     1    0.012    0.037
         2927.8   0.00  89.58  33.13   1.42  94.99  90.00      7    0.025     1    0.012    0.037
         2928.3   0.00  89.58  33.13   1.42  94.99  90.00      7    0.025     1    0.012    0.037
Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
         2928.8   0.00  89.58  33.13   1.42  94.99  90.00      7    0.025     1    0.012    0.037
         2929.3   0.00  89.58  33.13   1.42  94.99  90.00      7    0.025     1    0.012    0.037
         2929.8   0.00  89.58  33.13   1.42  94.99  90.00      7    0.025     1    0.012    0.037
         2930.3   0.00  89.58  33.93   1.42  94.99  90.00      7    0.025     1    0.012    0.037
         2930.8   0.00  89.58  34.16   1.42  94.99  90.00      7    0.025     1    0.012    0.037

在使用-gc选项来检查内存使用情况时,各个缩写字母的含义为,
- S0C: Current survivor space 0 capacity (KB). 年轻代第一个survivor空间容量
- S1C: Current survivor space 1 capacity (KB). 年轻代第二个survivor空间容量
- S0U: Survivor space 0 utilization (KB). 年轻代第一个survivor空间使用量
- S1U: Survivor space 1 utilization (KB). 年轻代第二个survivor空间使用量
- EC: Current eden space capacity (KB). 年轻代Eden空间容量
- EU: Eden space utilization (KB). 年轻代Eden空间使用量
- OC: Current old space capacity (KB). 年老代空间容量
- OU: Old space utilization (KB). 年老代空间使用量
- MC: Metaspace capacity (KB). 元空间容量
- MU: Metaspace utilization (KB). 元空间使用量
- CCSC: Compressed class space capacity (KB).
- CCSU: Compressed class space used (KB).
- YGC: Number of young generation garbage collection (GC) events. 年轻代空间GC次数
- YGCT: Young generation garbage collection time. 年轻代空间GC时间开销
- FGC: Number of full GC events. 整个堆区FULL GC次数
- FGCT: Full garbage collection time. 整个堆区FULL GC时间开销
- GCT: Total garbage collection time. 总GC时间开销

其它内存检查时所看到的缩写字母类似,更详细可以查看官方文档。

JVM的内存空间模型详细介绍见这里

3.3 jmap

简单命令,输出进程14120的内存使用情况,

$ jmap -heap 14120
Attaching to process ID 14120, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.111-b14

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

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 4208984064 (4014.0MB)
   NewSize                  = 88080384 (84.0MB)
   MaxNewSize               = 1402994688 (1338.0MB)
   OldSize                  = 176160768 (168.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 = 31981568 (30.5MB)
   used     = 21396720 (20.405502319335938MB)
   free     = 10584848 (10.094497680664062MB)
   66.90328629290471% used
From Space:
   capacity = 1048576 (1.0MB)
   used     = 524288 (0.5MB)
   free     = 524288 (0.5MB)
   50.0% used
To Space:
   capacity = 1048576 (1.0MB)
   used     = 0 (0.0MB)
   free     = 1048576 (1.0MB)
   0.0% used
PS Old Generation
   capacity = 176160768 (168.0MB)
   used     = 68010784 (64.86013793945312MB)
   free     = 108149984 (103.13986206054688MB)
   38.60722496396019% used

6179 interned Strings occupying 524264 bytes.

导出进程14120的内存使用情况到文件dump.tmp中,
jmap -dump:format=b,file=dump.tmp 14120
然后就可以使用 eclipse memory analyzer 进行分析,查看是否有内存泄露。

3.4 jinfo

获取进程14120的环境配置信息

$ jinfo 14120
Attaching to process ID 14120, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.111-b14
Java System Properties:

java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.111-b14
sun.boot.library.path = C:\Program Files\Java\jdk1.8.0_111\jre\bin
...
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
java.runtime.version = 1.8.0_111-b14
java.library.path = C:\Program Files\Java\jdk1.8.0_111\bin;
java.class.version = 52.0
...
os.name = Windows 7
sun.cpu.isalist = amd64

VM Flags:
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=264241152 -XX:MaxHeapSize=4208984064 -XX:MaxNewSize=1402994688 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=88080384 -XX:OldSize=176160768 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line:

3.5 jstack

获取进程14120的线程调用堆栈信息,通过查看线程堆栈,可以了解是否有死锁情况在发生(可以使用jconsole来辅助查看)。

$ jstack -l 14120
2018-08-22 17:49:07
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.111-b14 mixed mode):

"RMI TCP Connection(35)-172.20.16.89" #47 daemon prio=5 os_prio=0 tid=0x000000001d685000 nid=0x50f0 runnable [0x0000000021aee000]
   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 java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:265)
        - locked <0x00000006c9442578> (a java.io.BufferedInputStream)
        at java.io.FilterInputStream.read(FilterInputStream.java:83)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:550)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$1/1179263329.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
   Locked ownable synchronizers:
        - <0x000000076cd9db08> (a java.util.concurrent.ThreadPoolExecutor$Worker)
...
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000001bfa9000 nid=0x468c in Object.wait() [0x000000001d3be000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
        - locked <0x00000006c54ddeb0> (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)
...
"main" #1 prio=5 os_prio=0 tid=0x000000000253f000 nid=0x45d0 waiting on condition [0x000000000295f000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
        at java.lang.Thread.sleep(Native Method)
        at com.pphh.demo.Application.main(Application.java:23)
   Locked ownable synchronizers:
        - None

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x000000000238c800 nid=0x4404 runnable
...

JNI global references: 252