./jmap -heap:format=b 25003
./jstat -gc 25003 1000 1000
具体参数如下:
-class:统计class loader行为信息
-compile:统计编译行为信息
-gc:统计jdk gc时heap信息
-gccapacity:统计不同的generations(不知道怎么翻译好,包括新生区,老年区,permanent区)相应的heap容量情况
-gccause:统计gc的情况,(同-gcutil)和引起gc的事件
-gcnew:统计gc时,新生代的情况
-gcnewcapacity:统计gc时,新生代heap容量
-gcold:统计gc时,老年区的情况
-gcoldcapacity:统计gc时,老年区heap容量
-gcpermcapacity:统计gc时,permanent区heap容量
-gcutil:统计gc时,heap情况
-printcompilation:不知道干什么的,一直没用过。
jstat工具特别强大,有众多的可选项,详细查看堆内各个部分的使用量,以及加载类的数量。使用时,需加上查看进程的进程id,和所选参数。以下详细介绍各个参数的意义。
jstat -class pid:显示加载class的数量,及所占空间等信息。
jstat -compiler pid:显示VM实时编译的数量等信息。
jstat -gc pid:可以显示gc的信息,查看gc的次数,及时间。其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。
jstat -gccapacity:可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,如:PGCMN显示的是最小perm的内存使 用量,PGCMX显示的是perm的内存最大使用量,PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。其他的可以根据这个类 推,OC是old内纯的占用量。
jstat -gcnew pid:new对象的信息。
jstat -gcnewcapacity pid:new对象的信息及其占用量。
jstat -gcold pid:old对象的信息。
jstat -gcoldcapacity pid:old对象的信息及其占用量。
jstat -gcpermcapacity pid: perm对象的信息及其占用量。
jstat -util pid:统计gc信息统计。
jstat -printcompilation pid:当前VM执行的信息。
jstat -gcutil: 个人最喜欢用的,后面将详解。
除了以上一个参数外,还可以同时加上 两个数字,如:jstat -printcompilation 3024 250 6是每250毫秒打印一次,一共打印6次,还可以加上-h3每三行显示一下标题。
jmap是一个可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。使用方法 jmap -histo pid。如果连用SHELL jmap -histo pid>a.log可以将其保存到文本中去,在一段时间后,使用文本对比工具,可以对比出GC回收了哪些对象。jmap -dump:format=b,file=String 3024可以将3024进程的内存heap输出出来到String文件里。
jinfo的用处比较简单,就是能输出并修改运行时的java进程的运行参数。用法是jinfo -opt pid 如:查看2788的MaxPerm大小可以用 jinfo -flag MaxPermSize 2788。
jconsole是一个用java写的GUI程序,用来监控VM,并可监控远程的VM,非常易用,而且功能非常强。由于是GUI程序,这里就不详细介绍了,不会的地方可以参考SUN的官方文档。使用方法:命令行里打jconsole,选择进程就可以了。
使用jstat -gcutil 监控gc垃圾回收情况:
:~$ sudo jps
15734 WatchdogManager
15773 Resin
21947 Jps
:~$ sudo jstat -gcutil -t 15773 4s 50
Timestamp S0 S1 E O P YGC YGCT FGC FGCT GCT
5670.6 47.81 0.00 2.60 12.93 21.35 68 1.035 13 11.821 12.856
5674.7 47.81 0.00 6.65 12.93 21.35 68 1.035 13 11.821 12.856
5678.7 47.81 0.00 8.87 12.93 21.35 68 1.035 13 11.821 12.856
5682.7 47.81 0.00 10.35 12.93 21.35 68 1.035 13 11.821 12.856
5686.7 47.81 0.00 11.69 12.93 21.35 68 1.035 13 11.821 12.856
5690.7 47.81 0.00 14.15 12.93 21.35 68 1.035 13 11.821 12.856
5694.7 47.81 0.00 15.83 12.93 21.35 68 1.035 13 11.821 12.856
5698.7 47.81 0.00 17.07 12.93 21.35 68 1.035 13 11.821 12.856
5702.7 47.81 0.00 20.12 12.93 21.35 68 1.035 13 11.821 12.856
5706.6 47.81 0.00 23.22 12.93 21.35 68 1.035 13 11.821 12.856
5710.7 47.81 0.00 26.57 12.93 21.35 68 1.035 13 11.821 12.856
5714.7 47.81 0.00 29.78 12.93 21.35 68 1.035 13 11.821 12.856
5718.7 47.81 0.00 31.34 12.93 21.35 68 1.035 13 11.821 12.856
5722.7 47.81 0.00 33.45 12.93 21.35 68 1.035 13 11.821 12.856
5726.7 47.81 0.00 35.53 12.93 21.35 68 1.035 13 11.821 12.856
5730.7 47.81 0.00 37.80 12.93 21.35 68 1.035 13 11.821 12.856
5734.7 47.81 0.00 40.90 12.93 21.35 68 1.035 13 11.821 12.856
... ... ... ...
其中:
S0:Heap上的 Survivor space 0 段已使用空间的百分比
S1:Heap上的 Survivor space 1 段已使用空间的百分比
E: Heap上的 Eden space 段已使用空间的百分比
O: Heap上的 Old space 段已使用空间的百分比
P: Perm space 已使用空间的百分比
YGC:从程序启动到采样时发生Young GC的次数
YGCT:Young GC所用的时间(单位秒)
FGC:从程序启动到采样时发生Full GC的次数
FGCT:Full GC所用的时间(单位秒)
GCT:用于垃圾回收的总时间(单位秒)
针对上面的结果,稍微说说垃圾收集GC的基本操作过程如下:
首先,GC把内存大体分成4块,分别是old generation(年老代),eden(年轻代),以及survivor space1(ss1),survivor space0(ss0)。
当声明变量的时候,首先是把变量声明在年轻代中,然后当年轻代被填满,则发生次要垃圾收集,将其中存活对象复制到SS1中,再将年轻代清空。 继续在eden中声明对象,当eden再次填满,则再次发生次要垃圾收集,这次是把ss1的内容计算存活期,如果很长就复制到年老代,其余的存活的复制到 ss0,然后将ss1清空,并对eden进行前述的次要垃圾收集。 当年老代也被填满,则产生一次主要垃圾收集,非常耗费时间。