JVM监控分析工具之jps、jstat和jinfo
日常工作中难免会遇到一些Java的异难杂症,尤其是线上环境,不可能让你去debug,而jdk 自带的一些小工具能让你快速定位问题所在,这些工具都是基于命令行的,远程连接服务器在终端下就可以操作,可以说十分方便。
jps命令类似Linux下的ps,只不过显示的是虚拟机的进程号,后面介绍到的jstat等命令都需要用到这个虚拟机进程号
选项 | 作用 |
-q | 只输出LVMID,省略主类的名称 |
-m | 输出虚拟机进程启动时传给主类main()函数的参数 |
-l | 输出主类的全名,如果进程执行的是Jar包,输出Jar的路径 |
-v | 输出虚拟机进程启动时的JVM参数 |
通过一段源代码来测试一下这几个参数的含义
package org.bocai.jvm.monitor;
/**
* @author yikebocai@gmail.com
* @since 2013-3-25
*
*/
public class Testjps {
public static void main(String[] args) throws InterruptedException {
if (args != null && args.length == 1) {
System.out.println("Hello," + args[0] + "!");
}
while (true) {
Thread.sleep(1000);
}
}
}
在Eclipse里运行Testjps程序,然后在命令行下可以看到jps的执行结果:
xinbo.zhangxb@ALI-031884N /d/work/jvm/gc/target/classes (master)
$ jps
3596 Jps
920 Testjps
4056
xinbo.zhangxb@ALI-031884N /d/work/jvm/gc/target/classes (master)
$ jps -q
920
5544
4056
-m
参数是会显示传给main函数的参数,为了测试这个参数,我们在命令行下执行Testjps,并传入一个任意字符串参数。
xinbo.zhangxb@ALI-031884N /d/work/jvm/gc/target/classes (master)
$ java org/bocai/jvm/monitor/Testjps world
Hello,world!
xinbo.zhangxb@ALI-031884N /d/work/jvm/gc/target/classes (master)
$ jps -m
3944 Jps -m
4600 Testjps world
4056
-l
参数会输出主类的全名,如下所示
xinbo.zhangxb@ALI-031884N /d/work/jvm/gc/target/classes (master)
$ jps -l
4912 sun.tools.jps.Jps
4600 org/bocai/jvm/monitor/Testjps
4056
如果执行的jar包,则输出jar的路径。为了测试这一情况,我们先对class文件进行打包。首先先创建一个MANIFEST文件,用来指定jar包运行时的主类是什么,文件名可以任意取,内容如下:
Main-Class: org.bocai.jvm.monitor.Testjps
然后用指定的MNIFEST文件和Java源文件目录来打包:
jar cvfm mymanifest .
最后运行jar:
xinbo.zhangxb@ALI-031884N /d/work/jvm/gc/target/classes (master)
$ java -jar Testjps.jar jps
Hello,jps!
xinbo.zhangxb@ALI-031884N /d/work/jvm/gc/target/classes (master)
$ jps -l
288 sun.tools.jps.Jps
4056
2060 Testjps.jar
jstat(JVM Statistics Monitoring Tool)是用来监控JVM虚拟机运行时的各种状态信息,比如GC情况、类装载情况等。jstat的使用方法如下:
jstat -gc 1s 10
其中第一个可选参数如下所示,第二个参数表示输出内容的间隔时间,第三个参数表示输出的总次数
选项 | 作用 |
-class | 监控类加载、卸载数量、总空间及类加载所耗费的时间 |
-compiler | 输出JIT编译器编译过的方法、耗时等信息 |
-gc | 监视Java堆状况,包括Eden区、两个Survivor区、老年代、永久代的容量、已用空间、GC时间合计等信息 |
-gccapacity | 同-gc,额外输出堆中各个区使用到的最大和最小空间 |
-gccause | 同-gc,额外输出导致上一次GC的原因 |
-gcnew | 监视新生代GC情况 |
-gcnewcapacity | 同-gcnew,额外输出新生代各区使用到的最大和最小空间 |
-gcold | 监视老年代GC情况 |
-gcoldcapacity | 类似-gcnewcapactiy |
-gcpermcapacity | 输出永久代使用到的最大和最小空间 |
-gcutil | 同-gc,主要关注已使用空间的百分比 |
-printcompilation | 输出已被JIT编译的方法 |
下面先运行一个简单的程序:
package org.bocai.jvm.monitor;
/**
* VM Args:-Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8 -XX:+PrintGCDetails
*
* @author yikebocai@gmail.com
* @since 2013-3-26
*
*/
public class Testjstat {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) throws InterruptedException {
while (true) {
byte[] alloc1 = new byte[2 * _1MB];
byte[] alloc2 = new byte[2 * _1MB];
byte[] alloc3 = new byte[1 * _1MB];
// first Minor GC
byte[] alloc4 = new byte[4 * _1MB];
byte[] alloc5 = new byte[3 * _1MB];
// second Minor GC
byte[] alloc6 = new byte[4 * _1MB];
alloc1 = null;
alloc2 = null;
// first Full GC
byte[] alloc7 = new byte[2 * _1MB];
Thread.sleep(100);
}
}
}
先查看类加载情况:
xinbo.zhangxb@ALI-031884N /d/work/jvm/gc (master)
$ jstat -class 2124
Loaded Bytes Unloaded Bytes Time
14 16.4 0 0.0 0.03
其中几列所代表的含义如下:
Column | Description |
Loaded | 加载的Class文件数目 |
Bytes | 加载的字节数,KB为单位 |
Unloaded | 卸载的Class文件数目 |
Bytes | 卸载的字节数 |
Time | Class文件加载和卸载花费的时间 |
Column | Description |
Compiled | 执行的编译任务个数 |
Failed | 编译失败的个数 |
Invalid | 无效的编译任务个数 |
Time | 编译任务花费的时间 |
FailedType | 最后一个编译失败的编译类型 |
FailedMethod | 最后一个编译失败的Class名称和方法 |
Column | Description |
S0C | Survivor0的大小,单位为KB,下同 |
S1C | Survivor1的大小 |
S0U | Survivor0的使用大小 |
S1U | Survivor1的使用大小 |
EC | Eden区的大小 |
EU | Eden区的使用大小 |
OC | Old区的大小 |
OU | Old区的使用大小 |
PC | Perm区的大小 |
PU | Perm区的使用大小 |
YGC | Young GC次数 |
YGCT | YGC花费时间,单位为秒 |
FGC | Full GC次数 |
FGCT | FGC花费时间 |
GCT | GC总时间 |
Column | Description |
S0 | Survivor0使用的百分比,单位为% |
S1 | Survivor1使用的百分比 |
E | Eden区使用的百分比 |
O | Old区使用的百分比 |
P | Perm区使用的百分比 |
YGC | Young GC次数 |
YGCT | YGC花费时间,单位为秒 |
FGC | Full GC次数 |
FGCT | FGC花费时间 |
GCT | GC总时间 |
其它的几个参数说明请参见这里
jinfo(Configuration Info for Java)用来实时查看和调整虚拟机的各项参数,格式如下:
jinfo [option] pid
其中option选项主要包括:
Option | Description |
no option | 相当于同时使用-sysprops和-flags参数 |
-flag name | 打印某个指定的虚拟机参数值 |
-flag [+/-]name | enable或disbale某个JVM参数 |
-fag name=value | 设定指定的参数值 |
-fags | 打印所有的JVM参数 |
-sysprops | 打印所有系统属性信息 |
举例如下:
[7080@icbu-qa-006 bin]$ jinfo -flag PrintGCDetails 2041
-XX:+PrintGCDetails
[7080@icbu-qa-006 bin]$ jinfo -flag -PrintGCDetails 2041
[7080@icbu-qa-006 bin]$ jinfo -flag PrintGCDetails 2041
-XX:-PrintGCDetails
[7080@icbu-qa-006 bin]$ jinfo -flags 2041
Attaching to process ID 2041, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.0-b11
-Dprogram.name=run.sh -Xms1024m -Xmx1024m -XX:PermSize=256m -XX:SurvivorRatio=2 -XX:+UseParallelGC -Dtrace.flag=true -Dtrace.output.dir=/home/7080/work/intl-risk/deploy/trace/ -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=7050,server=y,suspend=n -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8 -DdisableIntlRMIStatTask=true -Dcom.alibaba.dragoon.KV_TASK_KEY=com.alibaba.intl.risk.comsat.RiskPaymentPerformanceTask -Dcommons.log.query.size.limit=100000 -Djava.endorsed.dirs=/usr/alibaba/jboss/lib/endorsed
7080@icbu-qa-006 ~]$ jinfo -sysprops 2041
Attaching to process ID 2041, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.0-b11
java.vendor = Sun Microsystems Inc.
sun.java.launcher = SUN_STANDARD
catalina.base = /home/7080/work/intl-risk/deploy/../.myjboss
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
catalina.useNaming = false
os.name = Linux
...
但不知道为什么无法设置某个参数的值:
[7080@icbu-qa-006 bin]$ jinfo -flag SurvivorRatio=5 2041
Exception in thread "main" java.io.IOException: Command failed in target VM
at sun.tools.attach.LinuxVirtualMachine.execute(LinuxVirtualMachine.java:200)
at sun.tools.attach.HotSpotVirtualMachine.executeCommand(HotSpotVirtualMachine.java:195)
at sun.tools.attach.HotSpotVirtualMachine.setFlag(HotSpotVirtualMachine.java:172)
at sun.tools.jinfo.JInfo.flag(JInfo.java:105)
at sun.tools.jinfo.JInfo.main(JInfo.java:58)
其它更多的用法请参见这里