Java
Java虚拟机

Java虚拟机10 - JVM工具之jps、jinfo、jstat、jmap及jhat

简介:Java开发工具包中提供了众多的虚拟机工具可供开发者使用。

1. jps

jps(JVM Process Status Tool)可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()方法所在的类)名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)。虽然功能比较单一,但它是使用频率最高的JDK命令行工具,因为其他的JDK工具大多需要输入它查询到的LVMID来确定要监控的是哪一个虚拟机进程。对于本地虚拟机进程来说,LVMID与操作系统的进程ID(Process Identifier,PID)是一致的,使用Windows的任务管理器或者UNIX的ps命令也可以查询到虚拟机进程的LVMID,但如果同时启动了多个虚拟机进程,无法根据进程名称定位时,那就只能依赖jps命令显示主类的功能才能区分了。

注:Oracle官方提供的jps命令的参考文档地址为https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

1.1. jps命令格式

jps命令格式为如下:

  • ubuntu@s100:~$ jps -help
  • usage: jps [-help]
  • jps [-q] [-mlvV] [<hostid>]

各类参数的意义如下:

选项 作用
-q 只输出LVMID,省略主类的名称
-m 输出虚拟机进程启动时传递给主类main()方法的参数
-l 输出主类的全名,如果进程执行的是Jar包,输出Jar包路径
-v 输出虚拟机进程启动时的JVM参数

1.2. jps使用演示

下面展示了jps各类参数的不同输出:

  • ubuntu@s100:~$ jps -q
  • 8037
  • 2281
  • ubuntu@s100:~$ jps -m
  • 2281 Bootstrap start
  • 8047 Jps -m
  • ubuntu@s100:~$ jps -l
  • 8057 sun.tools.jps.Jps
  • 2281 org.apache.catalina.startup.Bootstrap
  • ubuntu@s100:~$ jps -v
  • 8067 Jps -Dapplication.home=/soft/jdk1.8.0_65 -Xms8m
  • 2281 Bootstrap -Djava.util.logging.config.file=/soft/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Dignore.endorsed.dirs= -Dcatalina.base=/soft/tomcat -Dcatalina.home=/soft/tomcat -Djava.io.tmpdir=/soft/tomcat/temp

2. jinfo

jinfo(Configuration Info for Java)的作用是实时地查看和调整虚拟机各项参数。使用jps命令的-v参数可以查看虚拟机启动时显式指定的参数列表,但如果想知道未被显式指定的参数的系统默认值,除了去找资料外,就只能使用jinfo-flag选项进行查询了(如果只限于JDK 1.6或以上版本的话,使用java -XX:+PrintFlagsFinal查看参数默认值也是一个很好的选择),jinfo还可以使用-sysprops选项把虚拟机进程的System.getProperties()的内容打印出来。这个命令在JDK 1.5时期已经随着Linux版的JDK发布,当时只提供了信息查询的功能,JDK 1.6之后,jinfo在Windows和Linux平台都有提供,并且加入了运行期修改参数的能力,可以使用-flag[+|-]name或者-flag name=value修改一部分运行期可写的虚拟机参数值。JDK 1.6中,jinfo对于Windows平台功能仍然有较大限制,只提供了最基本的-flag选项。

注:Oracle官方提供的jinfo命令的参考文档地址为https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

2.1. jinfo命令格式

jinfo命令格式为如下:

  • ubuntu@s100:~$ jinfo
  • Usage:
  • jinfo [option] <pid>
  • (to connect to running process)
  • jinfo [option] <executable <core>
  • (to connect to a core file)
  • jinfo [option] [server_id@]<remote server IP or hostname>
  • (to connect to 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

各类参数的意义如下:

选项 作用
-flag 后跟参数名,用于打印参数值,或者设置某个参数值
-sysprops 打印System.getProperties()的内容

2.2. jinfo使用演示

  • $ > jinfo -flags 2168
  • Attaching to process ID 2168, please wait...
  • Debugger attached successfully.
  • Server compiler detected.
  • JVM version is 25.144-b01
  • Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4284481536 -XX:MaxNewSize=1428160512 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
  • Command line: -Djava.util.logging.config.file=C:\Java\apache-tomcat-7.0.52\conf\logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=C:\Java\apache-tomcat-7.0.52\endorsed -Dcatalina.base=C:\Java\apache-tomcat-7.0.52 -Dcatalina.home=C:\Java\apache-tomcat-7.0.52 -Djava.io.tmpdir=C:\Java\apache-tomcat-7.0.52\temp

3. jstat

jstat(JVM Statistics Monitoring Tool)是用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程[1]虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。

注:Oracle官方提供的jstat命令的参考文档地址为https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html

3.1. jstat命令格式

jstat命令格式为如下:

  • ubuntu@s100:~$ jstat
  • invalid argument count
  • Usage: jstat -help|-options
  • jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

其中-<option>可以是以下选项:

选项 作用
-class 监视类装载、卸载数量、总空间以及类装载所耗费的时间
-gc 监视Java堆状况,包括Eden区、两个survivor区、老年代、永久代等的容量、已用空间、GC时间合计等信息
-gccapaclty 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause -gcutil功能一样,但是会额外输出导致上一次GC产生的原因
-gcnew 监视新生代GC状况
-genewcapaclty 监视内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
-gcold 监视老年代GC状况
-geoldcapacity 监视内容与-gcold基本相同,输出主要关注使用到的最大、最小空间
-gepermcapaclty 输出永久代使用到的最大、最小空司
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已经被JIT编译的方法

对于命令格式中的VMID与LVMID需要特别说明一下:如果是本地虚拟机进程,VMID与LVMID是一致的,如果是远程虚拟机进程,那VMID的格式应当是:

  • [protocol:][//]lvmid[@hostname[:port]/servername]

注:当使用jstat来监视远程虚拟机进程时,需要远程主机提供RMI支持,Sun提供的jstatd工具可以很方便地建立远程RMI服务器。

3.2. jstat使用演示

以JDK 1.8环境为例,这里介绍几个常用的参数。

使用-gc参数来查看Java堆各个区域的垃圾回收状况,例如查看Tomcat的Java堆状况:

  • ubuntu@s100:~$ jps
  • 3300 Jps
  • 2281 Bootstrap
  • ubuntu@s100:~$ jstat -gc 2281
  • S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
  • 2112.0 2112.0 698.7 0.0 16896.0 5404.1 42368.0 17341.5 16768.0 16113.4 1920.0 1762.4 6 0.132 0 0.000 0.132

打印内容会反馈给我们列信息,这些列的含义如下:

  • S0C、S1C、S0U、S1U:Survivor0和Survivor1区的总量和使用量。
  • EC、EU:Eden区的总量和使用量。
  • OC、OU:Old区的总量和使用量。
  • MC、MU:Metaspace区总量和使用量。
  • CCSC、CCSU:压缩类空间总量和使用量。
  • YGC、YGCT:Young GC的次数和时间。
  • FGC、FGCT:Full GC的次数和时间。
  • GCT:总的GC时间。

在命令格式中,参数intervalcount代表查询间隔和次数,如果省略这两个参数,说明只查询一次。假设需要每250毫秒查询一次进程2281垃圾收集状况,一共查询20次,那命令应当是:

  • ubuntu@s100:~$ jstat -gc 2281 250 20
  • S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
  • 2112.0 2112.0 698.7 0.0 16896.0 10058.8 42368.0 17341.5 16768.0 16113.4 1920.0 1762.4 6 0.132 0 0.000 0.132
  • 2112.0 2112.0 698.7 0.0 16896.0 10058.8 42368.0 17341.5 16768.0 16113.4 1920.0 1762.4 6 0.132 0 0.000 0.132
  • 2112.0 2112.0 698.7 0.0 16896.0 10058.8 42368.0 17341.5 16768.0 16113.4 1920.0 1762.4 6 0.132 0 0.000 0.132
  • 2112.0 2112.0 698.7 0.0 16896.0 10058.8 42368.0 17341.5 16768.0 16113.4 1920.0 1762.4 6 0.132 0 0.000 0.132
  • 2112.0 2112.0 698.7 0.0 16896.0 10058.8 42368.0 17341.5 16768.0 16113.4 1920.0 1762.4 6 0.132 0 0.000 0.132
  • ...

-gccapacity参数可以看查看Java堆各个区域的内存状况:

  • ubuntu@s100:~$ jstat -gccapacity 2281
  • NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
  • 21120.0 336512.0 21120.0 2112.0 2112.0 16896.0 42368.0 673152.0 42368.0 42368.0 0.0 1064960.0 16768.0 0.0 1048576.0 1920.0 6 0

列的含义如下:

  • NGCMN:新生代使用到的最小内存大小(kB)。
  • NGCMX:新生代使用到的最大内存大小(kB)。
  • NGC:当前新生代使用到的内存大小(kB)。
  • S0C:当前Survivor0区使用到的内存大小(kB)。
  • S1C:当前Survivor1区使用到的内存大小(kB)。
  • EC:当前Eden区使用到的内存大小(kB)。
  • OGCMN:老年代使用到的最小内存大小(kB)。
  • OGCMX:老年代使用到的最小内存大小(kB)。
  • OGC:当前老年代使用到的内存大小(kB)。
  • OC:当前Old区使用到的内存大小(kB)。
  • MCMN:Metaspace区使用到的最小内存大小(kB)。
  • MCMX:Metaspace区使用到的最大内存大小(kB)。
  • MC:当前Metaspace区使用到的内存大小(kB)。
  • CCSMN:压缩类空间使用到的最小内存大小(kB)。
  • CCSMX:压缩类空间使用到的最大内存大小(kB)。
  • CCSC:当前压缩类空间使用到的内存大小(kB)。
  • YGC:Young GC发生的次数。
  • FGC:Full GC发生的次数。

-compiler参数可以输出输出JIT编译器编译过的方法、耗时等信息:

  • ubuntu@s100:~$ jstat -compiler 2281
  • Compiled Failed Invalid Time FailedType FailedMethod
  • 1858 0 0 5.00 0

列的含义如下:

  • Compiled:JIT编译成功的方法数量。
  • Failed:JIT编译失败的方法数量。
  • Invalid:无效的编译任务数量。
  • Time:编译总耗时。
  • FailedType:最后一次失败编译的类型。
  • FailedMethod:最后一次失败编译的类名和方法名。

4. jmap

jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件),还可以查询finalize执行队列、Java堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。

如果不使用jmap命令,要想获取Java堆转储快照,还有一些其他的方法:

  • 使用-XX:+HeapDumpOnOutOfMemoryError参数,可以让虚拟机在OOM异常出现之后自动生成dump文件。
  • 通过-XX:+HeapDumpOnCtrlBreak参数则可以使用+Ctrl++Break+键让虚拟机生成dump文件
  • 或者在Linux系统下通过Kill -3命令发送进程退出信号,也能拿到dump文件。

jmap有不少功能在Windows平台下都是受限的,除了生成dump文件的-dump选项和用于查看每个类的实例、空间占用统计的-histo选项在所有操作系统都提供之外,其余选项都只能在Linux/Solaris下使用。

注:Oracle官方提供的jmap命令的参考文档地址为https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html

4.1. jmap命令格式

jmap命令有以下的格式:

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

[option]参数有以下的几类取值:

选项 作用
-dump 生成Java堆转储快照。格式为-dump:[live,]format=b,file=<filename,其中live子参数说明是否只dump出存活的对象
-finalizerinfo 显示在F-Queue中等i寺Finalizer线程执行finalize方法的对象。只在Linux/Solaris平台下有效
-heap 显示Java堆详细信息,如使用哪种回收器、参数配置、分代状况等。只在Linux/Solaris平台下有效
-histo 显示堆中对象统计信息,包括类、实例数量、合计容量
-permstat 以ClassLoader为统计口径显示永久代内存状态。只在Linux/Solaris平台下有效
-F 当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照。只在Linux/Solaris平台下有效

4.2. jmap使用演示

如使用jmap命令导出某个JVM进程的堆转储文件:

  • ubuntu@s100:~$ jmap -dump:format=b,file=heap.hprof 2281
  • Dumping heap to /home/ubuntu/heap.hprof ...
  • Heap dump file created
  • ubuntu@s100:~$ ls -lh heap.hprof
  • -rw------- 1 ubuntu ubuntu 35M Oct 14 16:47 heap.hprof

查看某个进程堆中的对象统计信息:

  • ubuntu@s100:~$ jmap -histo 2281
  • num #instances #bytes class name
  • ----------------------------------------------
  • 1: 40653 9726648 [B
  • 2: 49649 8085016 [C
  • 3: 12086 1349168 [I
  • 4: 46202 1108848 java.lang.String
  • 5: 19071 610272 java.util.HashMap$Node
  • 6: 11520 460800 java.util.HashMap$ValueIterator
  • 7: 4981 438328 java.lang.reflect.Method
  • 8: 11271 360672 java.io.File
  • ...

1. jhat

Sun JDK提供jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,来分析jmap生成的堆转储快照。jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,可以在浏览器中查看。不过实事求是地说,在实际工作中,除非笔者手上真的没有别的工具可用,否则一般都不会去直接使用jhat命令来分析dump文件,主要原因有二:一是一般不会在部署应用程序的服务器上直接分析dump文件,即使可以这样做,也会尽量将dump文件复制到其他机器上进行分析,因为分析工作是一个耗时而且消耗硬件资源的过程,既然都要在其他机器进行,就没有必要受到命令行工具的限制了;另一个原因是jhat的分析功能相对来说比较简陋,后文将会介绍到的VisualVM,以及专业用于分析dump文件的Eclipse Memory Analyzer、IBM HeapAnalyzer等工具,都能实现比jhat更强大更专业的分析功能。

注:Oracle官方提供的jmap命令的参考文档地址为https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html

2. jhat使用演示

在前面我们使用jmap生成了一个heap.hprof的堆内存转储文件,我们可以使用jhat分析该文件:

  • ubuntu@s100:~$ jhat heap.hprof
  • Reading from heap.hprof...
  • Dump file created Sun Oct 14 01:47:30 PDT 2018
  • Snapshot read, resolving...
  • Resolving 322995 objects...
  • Chasing references, expect 64 dots................................................................
  • Eliminating duplicate references................................................................
  • Snapshot resolved.
  • Started HTTP server on port 7000
  • Server is ready.

从打印信息Started HTTP server on port 7000可知jhat命令启动了一个服务器监听在7000端口,可以通过浏览器访问该地址,可以得到一个页面:

1.jhat浏览器页面.png