jps、jinfo、jstat、jstack、jmap、jconsole等命令简介

本文详细介绍JDK自带的多个实用工具,如jinfo、jps、jstat、jstack、jmap及jconsole的功能与使用方法。通过具体案例演示如何运用这些工具诊断程序状态、监控内存使用情况、分析线程状况及进行堆转储等。

ref:http://blog.youkuaiyun.com/caihaijiang/article/details/6084325

JDK提供了几个很实用的工具,如下:

jinfo:观察运行中的java程序的运行环境参数:参数包括Java System属性和JVM命令行参数,java class path等信息。命令格式:jinfo 进程pid
jps:用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号。命令格式:jps   或 jps 远程服务ip地址    (默认端口1099)
jstat:一个极强的监视VM内存工具。可以用来监视VM内存内的各种堆和非堆的大小及其内存使用量。

jstack:可以观察到jvm中当前所有线程的运行情况和线程当前状态。, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。命令格式:jstack 进程pid
jmap:观察运行中的jvm物理内存的占用情况(如:产生哪些对象,及其数量)。命令格式:jmap [option] pid

      option参数如下:
             -heap
:打印jvm heap的情况
             -histo:打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。
             -histo:live :同上,但是只答应存活对象的情况
             -permstat:打印permanent generation heap情况

       使用jmap进行 heap dump的例子: jmap -dump:format=b,file=<filename> <pid>  

       打印内存统计图:jmap -histo:live <pid>

       结果中每行显示了当前堆中每种类类型的信息,包含被分配的实例个数及其消耗的字节数。选项“live”,表示只统计存活的对象

       需要注意的是,jmap不是运行分析工具,在生成统计图时JVM可能会暂停,因此当生成统计图时需要确认这种暂停对程序是可接受的。
jconsole:一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。

 

这些命令的使用,见官方文档:
jps:http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jps.html
jstat:http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jstat.html

jstack:http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstack.html
jmap:http://java.sun.com/j2se/1.5.0/docs/tooldocs/share/jmap.html
jconsole:http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html

 

 jstat的一些参数:

参数名称

描述

class

统计class loader行为信息。命令例子:jstat -class pid 1000 10 (每隔1秒监控一次,一共做10次),输出内容,含义如下:

LoadedNumber of classes loaded.
BytesNumber of Kbytes loaded.
UnloadedNumber of classes unloaded.
BytesNumber of Kbytes unloaded.
TimeTime spent performing class load and unload operations.

 

compile

统计编译行为信息。

gc

输出每个堆区域的当前可用空间以及已用空间(伊甸园,幸存者等等),GC执行的总次数,GC操作累计所花费的时间。

gccapactiy

输出每个堆区域的最小空间限制(ms)/最大空间限制(mx),当前大小,每个区域之上执行GC的次数。(不输出当前已用空间以及GC执行时间)。

gccause

输出-gcutil提供的信息以及最后一次执行GC的发生原因和当前所执行的GC的发生原因

gcnew

输出新生代空间的GC性能数据

gcnewcapacity

输出新生代空间的大小的统计数据。

gcold

输出老年代空间的GC性能数据。

gcoldcapacity

输出老年代空间的大小的统计数据。

gcpermcapacity

输出持久带空间的大小的统计数据。

gcutil

输出每个堆区域使用占比,以及GC执行的总次数和GC操作所花费的事件。

 

你可以只关心那些最常用的命令,你会经常用到 -gcutil (或-gccause), -gc and –gccapacity。

·         -gcutil 被用于检查堆间的使用情况,GC执行的次数以及GC操作所花费的时间。

·         -gccapacity以及其他的参数可以用于检查实际分配内存的大小。

不同的jstat参数输出不同类型的列,如下表所示,根据你使用的”jstat option”会输出不同列的信息。

说明 Jstat参数
S0C 输出Survivor0空间的大小。单位KB。 -gc
-gccapacity
-gcnew
-gcnewcapacity
S1C 输出Survivor1空间的大小。单位KB。 -gc
-gccapacity
-gcnew
-gcnewcapacity
S0U 输出Survivor0已用空间的大小。单位KB。 -gc
-gcnew
S1U 输出Survivor1已用空间的大小。单位KB。 -gc
-gcnew
EC 输出Eden空间的大小。单位KB。 -gc
-gccapacity
-gcnew
-gcnewcapacity
EU 输出Eden已用空间的大小。单位KB。 -gc
-gcnew
OC 输出老年代空间的大小。单位KB。 -gc
-gccapacity
-gcold
-gcoldcapacity
OU 输出老年代已用空间的大小。单位KB。 -gc
-gcold
PC 输出持久代空间的大小。单位KB。 -gc
-gccapacity
-gcold
-gcoldcapacity
-gcpermcapacity
PU 输出持久代已用空间的大小。单位KB。 -gc
-gcold
YGC 新生代空间GC时间发生的次数。 -gc
-gccapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
YGCT 新生代GC处理花费的时间。 -gc
-gcnew
-gcutil
-gccause
FGC full GC发生的次数。 -gc
-gccapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
FGCT full GC操作花费的时间 -gc
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
GCT GC操作花费的总时间。 -gc
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-gccause
NGCMN 新生代最小空间容量,单位KB。 -gccapacity
-gcnewcapacity
NGCMX 新生代最大空间容量,单位KB。 -gccapacity
-gcnewcapacity
NGC 新生代当前空间容量,单位KB。 -gccapacity
-gcnewcapacity
OGCMN 老年代最小空间容量,单位KB。 -gccapacity
-gcoldcapacity
OGCMX 老年代最大空间容量,单位KB。 -gccapacity
-gcoldcapacity
OGC 老年代当前空间容量制,单位KB。 -gccapacity
-gcoldcapacity
PGCMN 持久代最小空间容量,单位KB。 -gccapacity
-gcpermcapacity
PGCMX 持久代最大空间容量,单位KB。 -gccapacity
-gcpermcapacity
PGC 持久代当前空间容量,单位KB。 -gccapacity
-gcpermcapacity
PC 持久代当前空间大小,单位KB -gccapacity
-gcpermcapacity
PU 持久代当前已用空间大小,单位KB -gc
-gcold
LGCC 最后一次GC发生的原因 -gccause
GCC 当前GC发生的原因 -gccause
TT 老年化阈值。被移动到老年代之前,在新生代空存活的次数。 -gcnew
MTT 最大老年化阈值。被移动到老年代之前,在新生代空存活的次数。 -gcnew
DSS Adequate size of survivor in KB
幸存者区所需空间大小,单位KB。
-gcnew
参考文章:http://www.importnew.com/2057.html

 

下面内容,摘自:http://jameswxx.javaeye.com/blog/731763

在本机执行 jstat -gcutil 340 10000,这个命令是每个10秒钟输出一次jvm的gc信息,10000指的是间隔时间为10000毫秒。屏幕上显示如下信息(我只取了第一行,因为是按的一定频率显示,所以实际执行的时候,会有很多行):

   S0       S1       E        O          P       YGC     YGCT    FGC    FGCT     GCT  
 54.62   0.00  42.87  43.52  86.24   1792    5.093     33       7.670   12.763

[xhtml]  view plain copy
  1. S0:新生代的susvivor0区,空间使用率为54..62%  
  2. S1:新生代的susvivor1区,空间使用率为0.00%(因为还没有执行第二次minor收集)  
  3. E:eden区,空间使用率42.87%  
  4. O:旧生代,空间使用率43.52%  
  5. P:持久带,空间使用率86.24%  
  6. YGC:minor gc执行次数1792次  
  7. YGCT:minor gc耗费的时间5.093毫秒  
  8. FGC:full gc执行次数33  
  9. FGCT:full gc耗费的时间7.670毫秒  
  10. GCT:gc耗费的总时间12.763毫秒   

如果young gc和full gc能够正常发生,而且都能有效回收内存,常驻内存区变化不明显,则说明java内存释放情况正常,垃圾回收及时,java内存泄露的几率就会大大降低。但也不能说明一定没有内存泄露。


每次young gc消耗的时间,可以用相间隔的两行YGCT相减得到。每次full gc消耗的时间,可以用相隔的两行FGCT相减得到

官方文档的一个例子:



[plain]  view plain copy
  1. Using the gcutil option  
  2.   
  3. This example attaches to lvmid 21891 and takes 7 samples at 250 millisecond intervals and displays the output as specified by the -gcutil option.  
  4.   
  5. jstat -gcutil 21891 250 7  
  6.   S0     S1     E      O      P     YGC    YGCT    FGC    FGCT     GCT  
  7.  12.44   0.00  27.20   9.49  96.70    78    0.176     5    0.495    0.672  
  8.  12.44   0.00  62.16   9.49  96.70    78    0.176     5    0.495    0.672  
  9.  12.44   0.00  83.97   9.49  96.70    78    0.176     5    0.495    0.672  
  10.   0.00   7.74   0.00   9.51  96.70    79    0.177     5    0.495    0.673  
  11.   0.00   7.74  23.37   9.51  96.70    79    0.177     5    0.495    0.673  
  12.   0.00   7.74  43.82   9.51  96.70    79    0.177     5    0.495    0.673  
  13.   0.00   7.74  58.11   9.51  96.71    79    0.177     5    0.495    0.673  
  14. The output of this example shows that a young generation collection occurred between the 3rd an

例子: 

1. 发现问题

    最近在检查爬虫程序运行情况的时候发现采集速度非常慢,查看cpu占用率的时候发现有一个内核一直是100%,按理说多线程的程序不应该会出现这样的情况。第一反应就是用jstack -l [pid]把线程dump出来查看栈情况,但没发现什么异常。然后就考虑用jmap -heap [pid]把内存使用情况打印出来看看,奇怪的是出现好几次连接不上的情况,等打印出来发现居然旧生代已经满了。把内存调大,发现过不了一会又是这样,确实非常蹊跷。

2. 深入调查

    看来问题比较棘手,只好用更细致的方式去分析了。一方面打开了GC日志,同时在运行时用jstat -gcutil [pid] 1000来跟踪GC情况。现象很奇怪,旧生代空间缓慢增长,但突然新生代内存占用100%,旧生代紧接着也变成100%,然后就一直处于full gc,但内存丝毫没有减少,整个过程持续了5分钟。(截图忘记保存了,悲剧...)

    看现象就是对象爆炸,但程序已经运行很久了,如果有这么严重的bug应该早就发现了。严谨起见,我用jmap -histo [pid]把程序的对象情况打印出来,结果非常惊讶。

 
  1. num     #instances         #bytes  class name 
  2. --------------------------------------------- 
  3.   1:      30110820     1204432800  org.jsoup.parser.ParseError 
  4.   2:         33076      156025088  [Ljava.lang.Object; 
  5.   3:         68836       98796360  [C 

    系统中居然出现那么多ParserError对象,这个是程序中用到的一个Jsoup开源包里面的东西。看命名像是一个Exception,但查看源码时才发现居然是一个Class。至于这个东西从哪里蹦出来的呢?!我在现象出现的时候打印了下线程栈信息,果然定位到了生成这个对象的那个位置。

    在源码中找到相应的实现,主要是调用了这样一个方法:

 
  1. private boolean trackErrors = true;
  2. ......
  3. void error(TokeniserState state) { 
  4.     if (trackErrors) 
  5.         errors.add(new ParseError("Unexpected character in input", reader.current(), state, reader.pos())); 

    这里有一个trackErrors做开关,默认是true,但找了一下,居然没有最外层的方法去控制它,而errors这个对象也是一个private值,没有任何调用,可能是作者自己测试用的。

3. 问题的处理

    原因调查清楚,处理就很简单了。直接把源码中trackErrors的默认值改成false,再确认了一下其他相关调用的方法,然后重新编译打包,把原始包替换了。

4. 总结

    找问题还是要先分析出可能的原因,然后借用工具去定位问题,很多时候数据比经验更可靠。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值