JVM的常用性能监控工具jps、jstat、jinfo、jmap、jhat、jstack

文章目录


参考链接
jvm系列五:监测命令(jvisualvm jps jstat jmap jhat jstack jinfo)及dump堆内存快照分析

给虚拟机定位问题之前需要有一定的虚拟机基础,比如说内存分配与回收技术。
给一个系统定位问题的时候,知识,经验是关键基础、数据是依据、工具是运用知识处理数据的手段,常见的数据包括:运行日志、异常堆栈、GC日志、线程快照(threaddump/javacode文件)、堆转储快照(heapdump、hprof),下面列出一下常用的JDK的常用命令行工具。

JDK的命令行工具都位于你的安装目录下C:\Program Files\Java\jdk1.6.0_43\bin我的安装目录是这个,平时我们用的java、javac都是位于这个目录下面的。

使用JDK的监控命令是基于JMX来管理的,默认开启是在JDK1.6之后的版本,如果是JDk1.5,需要设置JVM参数-Dcom.sun.management.jmxremote来开启。

常用的JDK监控和故障处理工具

名称 主要作用
jps JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程
jstat JVM Statistics Monitoring Tool,用于手机HotSpot虚拟机各方面的运行数据
jinfo Configuration info for java,显示虚拟机配置信息
jmap Memory Map for java,生成虚拟机的内存转储快照(heapdump)
jhat JVM Heap Dump Browser,用于分析heapdump文件,它会建立一个Http/HTML服务器,让用户可以在浏览器上查看分析结果
jstack Stack Trace for java,显示虚拟机的线程快照。

####JPS
ps是JVM的一个常用命令,类似linux中的ps命令。jps是查看java进程信息的命令;ps是查看linux系统中进程的命令

格式

  • jps [ options ] [ hostid ]

参数说明

  • options
    • -q 只输出java进程的进程id
    • -l 输出java进程的进程id和main方法的类全名
    • -m 输出java进程的进程id和main方法的入参
    • -v 输出java进程的进程id和jvm的入参
    • -V 输出java进程的进程id和通过flag文件传入jvm的参数
  • hostid
    • 命令对应的服务器ip,默认不加参数,默认查看本机,要查看远程机器的java 进程,需要远程机器开始RMI服务,hostid就是RMI注册表的主机名(叫IP也可以)

JPS命令效果~~~

[root@localhost ~]# man jps
[root@localhost ~]# jps -q
28801
[root@localhost ~]# jps -m
28815 Jps -m
[root@localhost ~]# jps -l
28829 sun.tools.jps.Jps
[root@localhost ~]# jps -v
28843 Jps -Denv.class.path=.:/root/soft/jdk1.7.0_67/lib:/root/soft/jdk1.7.0_67/jre/lib -Dapplication.home=/root/soft/jdk1.7.0_67 -Xms8m
[root@localhost ~]# 

####jstat
jstat是用于监视虚拟各种运行状态信息的命令行工具,它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

命令格式
参考链接
JVM学习之jstat使用方法
jstat命令查看jvm的GC情况 (以Linux为例)

jstat [Options]  -t vmid [interval] [count]

说明
Options 选项参数
-t 这个是打印一下时间
vmid 进程ID(如果是查看远程虚拟机的信息,这里需要特别设置~~~),可以考虑使用jstatd工具建立RMI服务器。
inerval 停顿时间,默认毫秒,可以设置为秒
count 查询次数,默认异常

option选项

选项 作用
-class 监视类装载、卸载数量、总空间以及类装载所消耗的时间
-compiler 显示JIT编译过的方法、耗时等信息;
-gc 监视java堆状况,包括Eden区,两个Survivor区,老年代,永久代等的容量,已用空间、GC时间等信息;
-gccapacity 显示各个代的容量以及使用情况;
-gccause 显示垃圾回收的相关信息(和-gcutil差不多),同时显示最后一次或当前正在发生的垃圾回收的诱因;
-gcnew 显示新生代信息;
-gcnewcapacity 显示新生代大小和使用情况;
-gcold 显示老年代和永久代的信息;
-gcoldcapacity 显示老年代的大小;
-gcpermcapacity 输出永久代使用到的最大和最小空间
-gcutil 显示垃圾收集信息;
-printcompilation 输出JIT编译的方法信息;

常见用法

[root@localhost ~]# jstat -gc  29170 500  5
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
2560.0 2560.0 2538.0  0.0   30720.0  19542.3   39936.0    11552.8   21504.0 15790.0      4    0.058   0      0.000    0.058
2560.0 2560.0 2538.0  0.0   30720.0  19542.3   39936.0    11552.8   21504.0 15790.0      4    0.058   0      0.000    0.058
2560.0 2560.0 2538.0  0.0   30720.0  19542.6   39936.0    11552.8   21504.0 15790.0      4    0.058   0      0.000    0.058
2560.0 2560.0 2538.0  0.0   30720.0  19542.6   39936.0    11552.8   21504.0 15790.0      4    0.058   0      0.000    0.058
2560.0 2560.0 2538.0  0.0   30720.0  19543.0   39936.0    11552.8   21504.0 15790.0      4    0.058   0      0.000    0.058
[root@localhost ~]# 

上面这个命令就是查看进程是29170是gc情况,每500毫秒查询一次,一共查询五次。
结果分析

  • S0C: Survivor0(幸存区0)大小(KB)
  • S1C: Survivor1(幸存区1)1大小(KB)
  • S0U: Survivor0(幸存区0)已使用大小(KB)
  • S1U: Survivor1(幸存区1)已使用大小(KB)
  • EC : Eden(伊甸区)大小(KB)
  • EU : Eden(伊甸区)已使用大小(KB)
  • OC :老年代大小(KB)
  • OU : 老年代已使用大小(KB)
  • PC : Perm永久代大小(KB)
  • PU : Perm永久代已使用大小(KB)
  • YGC:新生代GC个数
  • YGCT:新生代GC的耗时(秒)
  • FGC :Full GC次数
  • FGCT:Full GC耗时(秒)
  • GCT :GC总耗时(秒)

jstat的其他option可参考上面的两个链接。

####jinfo
参考链接
jinfo:JAVA进程运行时修改虚拟机参数利器(无需重启)
JVM命令jinfo

格式
jinfo [option] pid

jinfo的基本用法

[root@localhost ~]# jinfo
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 

解释

  • option
    • no option 输出全部的参数和系统属性
    • -flag name 输出对应名称的参数
    • -flag [+|-]name 开启或者关闭对应名称的参数
    • -flag name=value 设定对应名称的参数
    • -flags 输出全部的参数
    • -sysprops 输出系统属性

jinfo的作用是实时查看和调整虚拟机各项参数,使用jps命令的-v参数key查看虚拟机启动时显示指定的参数列表。

[root@localhost ~]# jps -v
29170 Bootstrap -Djava.util.logging.config.file=/root/geth/apache-tomcat-8.5.23/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dcatalina.base=/root/geth/apache-tomcat-8.5.23 -Dcatalina.home=/root/geth/apache-tomcat-8.5.23 -Djava.io.tmpdir=/root/geth/apache-tomcat-8.5.23/temp
32016 Jps -Denv.class.path=.:/root/soft/jdk1.7.0_67/lib:/root/soft/jdk1.7.0_67/jre/lib -Dapplication.home=/root/soft/jdk1.7.0_67 -Xms8m
[root@localhost ~]# 

如果想知道未被显示指定的参数,可以使用jinfo -flag来查看(jinfo -flag PrintGC 29170),在JDK1.6版本以上可以使用-XX:+PrintFlagsFinal来打印默认参数值([root@localhost ~]# java -XX:+PrintFlagsFinal -version |grep manageable),jinfo还可以使用-sysprops把虚拟机进程的System.getProperties()内容打印出来,jinfo可以通过-flag [+|-] to enable or disable the named VM flag动态设置JVM参数。

并不是所有的JVM参数都是可以改的,通过java -XX:+PrintFlagsFinal -version |grep manageable查看哪些可改。

####jmap java内存映象工具
参考链接
java -XX:+HeapDumpOnOutOfMemoryError的应用
JVM参数-XX:+HeapDumpOnOutOfMemoryError 在哪里设置,如何设置?

jmap命令用于生成堆转储快照(heapdump或者dump文件),如果不使用jmap命令,可以是暴力手段获取dump文件,如设置JVM参数-XX:+HeapDumpOnOutOfMemoryError这样程序在发生OOM异常的时候回生成dump文件,需要生成dump文件的时候,最后设置下-XX:HeapDumpPath=${目录}dump文件的生成目录,免得到处找。在window上可以设置-XX:+HeapDumpOnCtrlBreak参数,然后在你的tomcat的console使用[Ctrl]+[Break]两个键来生成dump文件,在linux还可以使用kill -3命令生成dump文件。jmap不仅能生成dump文件,还可以查询finalize执行队列、Java堆和永久代的详细信息,如当前使用率、当前使用的是哪种收集器等。

jmap命令在window上还是有很多的局限性,推荐还是在linux上使用。

jmap命令格式
jmap [option] LVMID

option参数

  • -dump : 生成堆转储快照,格式为-dump::live,format=b,file= pid(dump堆到文件,format指定输出格式,live指明是活着的对象,file指定文件名) > jmap -dump:live,format=b,file=dump.hprof pid
  • -finalizerinfo : 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
  • -heap : 显示Java堆详细信息,如使用哪种回收器,参数配置,分代状况。
  • -histo : 显示堆中对象的统计信息,包括类、实例数量、合计容量。
  • -permstat : 以ClassLoader为统计口径显示永久带内存信息
  • -F : 当-dump没有响应时,强制生成dump快照

使用案例
生成dump文件,查看当前目录是否生成文件。

[root@localhost ~]# jmap -dump:live,format=b,file=dump.hprof 29170
[root@localhost ~]# jmap -heap 29170
Attaching to process ID 28920, please wait...
  Debugger attached successfully.
  Server compiler detected.
  JVM version is 24.71-b01  

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

  Heap Configuration: //堆内存初始化配置
     MinHeapFreeRatio = 0 //对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
     MaxHeapFreeRatio = 100 //对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
     MaxHeapSize      = 2082471936 (1986.0MB) //对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
     NewSize          = 1310720 (1.25MB)//对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
     MaxNewSize       = 17592186044415 MB//对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
     OldSize          = 5439488 (5.1875MB)//对应jvm启动参数-XX:OldSize=:设置JVM堆的‘老生代’的大小
     NewRatio         = 2 //对应jvm启动参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
     SurvivorRatio    = 8 //对应jvm启动参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值 
     PermSize         = 21757952 (20.75MB)  //对应jvm启动参数-XX:PermSize=:设置JVM堆的‘永生代’的初始大小
     MaxPermSize      = 85983232 (82.0MB)//对应jvm启动参数-XX:MaxPermSize=:设置JVM堆的‘永生代’的最大大小
     G1HeapRegionSize = 0 (0.0MB)  

  Heap Usage://堆内存使用情况
  PS Young Generation
  Eden Space://Eden区内存分布
     capacity = 33030144 (31.5MB)//Eden区总容量
     used     = 1524040 (1.4534378051757812MB)  //Eden区已使用
     free     = 31506104 (30.04656219482422MB)  //Eden区剩余容量
     4.614088270399305% used //Eden区使用比率
  From Space:  //其中一个Survivor区的内存分布
     capacity = 5242880 (5.0MB)
     used     = 0 (0.0MB)
     free     = 5242880 (5.0MB)
     0.0% used
  To Space:  //另一个Survivor区的内存分布
     capacity = 5242880 (5.0MB)
     used     = 0 (0.0MB)
     free     = 5242880 (5.0MB)
     0.0% used
  PS Old Generation //当前的Old区内存分布
     capacity = 86507520 (82.5MB)
     used     = 0 (0.0MB)
     free     = 86507520 (82.5MB)
     0.0% used
  PS Perm Generation//当前的 “永生代” 内存分布
     capacity = 22020096 (21.0MB)
     used     = 2496528 (2.3808746337890625MB)
     free     = 19523568 (18.619125366210938MB)
     11.337498256138392% used  

  670 interned Strings occupying 43720 bytes.

-histo
打印堆的对象统计,包括对象数、内存大小等等 (因为在dump:live前会进行full gc,如果带上live则只统计活对象,因此不加live的堆大小要大于加live堆的大小 )

[root@localhost ~]# jmap -histo:live 29170 | more

 num     #instances         #bytes  class name
----------------------------------------------
   1:         29197        5386920  [C
   2:         29950        4147800  
   3:         29950        3844912  
   4:          2619        3123992  
   5:          2619        1847672  
   6:          2324        1843040  
   7:          5900         779256  [B
   8:         28186         676464  java.lang.String
   9:         13679         437728  java.util.HashMap$Entry
  10:           757         398632  
  11:          4447         355760  java.lang.reflect.Method
  12:          2887         350144  java.lang.Class
  13:          3906         245072  [S
  14:          4331         229456  [[I
  15:           958         162208  [Ljava.util.HashMap$Entry;
  16:          4687         149984  java.util.concurrent.ConcurrentHashMap$HashEntry
  17:           251         136544  
  18:          2346         105320  [Ljava.lang.Object;
  19:          1555          74640  java.util.HashMap
  20:          3967          63472  java.lang.Object
  21:           691          50504  [Ljava.lang.String;
  22:          2495          50128  [Ljava.lang.Class;
--More--

xml class name是对象类型,说明如下

B  byte
C  char
D  double
F  float
I  int
J  long
Z  boolean
[  数组,如[I表示int[]
[L+类名 其他对象

-permstat

打印Java堆内存的永久保存区域的类加载器的智能统计信息。对于每个类加载器而言,它的名称、活跃度、地址、父类加载器、它所加载的类的数量和大小都会被打印。此外,包含的字符串数量和大小也会被打印。

[root@localhost ~]# jmap -permstat 29170
Attaching to process ID 29170, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.65-b04
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness..................................................liveness analysis may be inaccurate ...
class_loader	classes	bytes	parent_loader	alive?	type

	1891	10952768	  null  	live	
0x00000000c5681f88	1	3064	0x00000000c56e2dc8	dead	sun/reflect/DelegatingClassLoader@0x00000000bfe4fc00
0x00000000c58a9a88	2	11168	0x00000000c56e2dc8	live	org/apache/catalina/loader/ParallelWebappClassLoader@0x00000000c0a36858
0x00000000c5591158	1	3032	0x00000000c56e2dc8	dead	sun/reflect/DelegatingClassLoader@0x00000000bfe4fc00
0x00000000c5682008	1	3064	0x00000000c56e2dc8	dead	sun/reflect/DelegatingClassLoader@0x00000000bfe4fc00
0x00000000c51be6a8	1	3032	0x00000000c56e2dc8	dead	sun/reflect/DelegatingClassLoader@0x00000000bfe4fc00
0x00000000c558ff78	1	3072	0x00000000c56e2dc8	dead	sun/reflect/DelegatingClassLoader@0x00000000bfe4fc00
0x00000000c5681f08	1	3032	0x00000000c56e2dc8	dead	sun/reflect/DelegatingClassLoader@0x00000000bfe4fc00
0x00000000c5682088	1	3064	0x00000000c56e2dc8	dead	sun/reflect/DelegatingClassLoader@0x00000000bfe4fc00
0x00000000c51c1518	1	3064	0x00000000c56e2dc8	dead	sun/reflect/DelegatingClassLoader@0x00000000bfe4fc00

####jhat
jhat(JVM Heap Analysis Tool)命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看。在此要注意,一般不会直接在服务器上进行分析,因为jhat是一个耗时并且耗费硬件资源的过程,一般把服务器生成的dump文件复制到本地或其他机器上进行分析,加载dump文件需要比dump文件更大的内存,一般在64位的JDK的服务器上面进行。

命令格式

jhat [dumpfile]

参数

  • -stack false|true 关闭对象分配调用栈跟踪(tracking object allocation call stack)。 如果分配位置信息在堆转储中不可用. 则必须将此标志设置为 false. 默认值为 true.>
  • -refs false|true 关闭对象引用跟踪(tracking of references to objects)。 默认值为 true. 默认情况下, 返回的指针是指向其他特定对象的对象,如反向链接或输入引用(referrers or incoming references), 会统计/计算堆中的所有对象。>
  • -port port-number 设置 jhat HTTP server 的端口号. 默认值 7000.>
  • -exclude exclude-file 指定对象查询时需要排除的数据成员列表文件(a file that lists data members that should be excluded from the reachable objects query)。 例如, 如果文件列列出了 java.lang.String.value , 那么当从某个特定对象 Object o 计算可达的对象列表时, 引用路径涉及 java.lang.String.value 的都会被排除。>
  • -baseline exclude-file 指定一个基准堆转储(baseline heap dump)。 在两个 heap dumps 中有相同 object ID 的对象会被标记为不是新的(marked as not being new). 其他对象被标记为新的(new). 在比较两个不同的堆转储时很有用.>
  • -debug int 设置 debug 级别. 0 表示不输出调试信息。 值越大则表示输出更详细的 debug 信息.>
  • -version 启动后只显示版本信息就退出>
  • -J< flag > 因为 jhat 命令实际上会启动一个JVM来执行, 通过 -J 可以在启动JVM时传入一些启动参数. 例如, -J-Xmx512m 则指定运行 jhat 的Java虚拟机使用的最大堆内存为 512 MB. 如果需要使用多个JVM启动参数,则传入多个 -Jxxxxxx.

使用命令

[root@localhost ~]# jhat dump.hprof
Reading from dump.hprof...
Dump file created Sun May 06 15:51:21 CST 2018
Snapshot read, resolving...
Resolving 154100 objects...
Chasing references, expect 30 dots..............................
Eliminating duplicate references..............................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

启动好了就可以访问http服务器7000端口了,这个还不太会看~~~

一般查看堆异常情况主要看这个两个部分:

  • Show instance counts for all classes (excluding platform),平台外的所有对象信息。
  • Show heap histogram 以树状图形式展示堆情况。

####jstack(java堆栈跟踪工具)
jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

命令格式

jstack [option] LVMID

option参数

  • -F : 当正常输出请求不被响应时,强制输出线程堆栈
  • -l : 除堆栈外,显示关于锁的附加信息
  • -m : 如果调用到本地方法的话,可以显示C/C++的堆栈

实例

[root@localhost bin]# jstack -l 29170 |more
2018-05-06 16:29:50
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.65-b04 mixed mode):

"Attach Listener" daemon prio=10 tid=0x00007f5cdc001000 nid=0x7db9 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"ajp-nio-8009-AsyncTimeout" daemon prio=10 tid=0x00007f5d103e5000 nid=0x7238 waiting on condition [0x00007f5d041d0000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at org.apache.coyote.AbstractProtocol$AsyncTimeout.run(AbstractProtocol.java:1211)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None

"ajp-nio-8009-Acceptor-0" daemon prio=10 tid=0x00007f5d103e2800 nid=0x7237 runnable [0x00007f5d042d1000]
   java.lang.Thread.State: RUNNABLE
	at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:241)
	- locked <0x00000000c5735c60> (a java.lang.Object)
	at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:455)
	at java.lang.Thread.run(Thread.java:745)

分析

线程状态
想要通过jstack命令来分析线程的情况的话,首先要知道线程都有哪些状态,下面这些状态是我们使用jstack命令查看线程堆栈信息时可能会看到的线程的几种状态:

  • NEW,未启动的。不会出现在Dump中。
  • RUNNABLE,在虚拟机内执行的。
  • BLOCKED,受阻塞并等待监视器锁。
  • WATING,无限期等待另一个线程执行特定操作。
  • TIMED_WATING,有时限的等待另一个线程的特定操作。
  • TERMINATED,已退出的。

参考这个链接,分析线程堆栈
Java命令学习系列(二)——Jstack

你可能感兴趣的:(深入理解JAVA虚拟机)