jvm分析备忘
是什么 jps 查看所有的jvm进程,包括进程ID,进程启动的路径等等。 jstack 观察jvm中当前所有线程的运行情况和线程当前状态。 系统崩溃了?如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。 系统hung住了?jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。 jstat jstat利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对进程的classloader,compiler,gc情况;特别的,一个极强的监视内存的工具,可以用来监视VM内存内的各种堆和非堆的大小及其内存使用量,以及加载类的数量。 jmap 监视进程运行中的jvm物理内存的占用情况,该进程内存内,所有对象的情况,例如产生了哪些对象,对象数量; 系统崩溃了?jmap 可以从core文件或进程中获得内存的具体匹配情况,包括Heap size, Perm size等等 jinfo 观察进程运行环境参数,包括Java System属性和JVM命令行参数 系统崩溃了?jinfo可以从core文件里面知道崩溃的Java应用程序的配置信息 用法 jps jps [options] [hostid] 如果不指定hostid就默认为当前主机或服务器。 Jps -ml jstack -l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况 -m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法) jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。下面我们来一个实例找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息,用到的命令有ps、top、printf、jstack、grep。 1. 第一步先找出Java进程ID (ps -ef|grep java |grep springWK –color=auto) 21711 2.第二步找出该进程内最耗费CPU的线程,可以使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我这里用第三个 TIME列就是各个Java线程耗费的CPU时间,CPU时间最长的是线程ID为21742的线程,用 printf “%x\n” 21742 得到21742的十六进制值为54ee jstack 21711 | grep 54ee jstat 具体参数如下: -class:统计class loader行为信息 -compile:统计编译行为信息 -gc:统计jdk gc时heap信息 -gccapacity:统计不同的generations(包括新生区,老年区,permanent区)相应的heap容量情况 -gccause:统计gc的情况,(同-gcutil)和引起gc的事件 -printcompilation:不知道干什么的,一直没用过。 一般比较常用的几个用法: $ jstat -class 2840 1000 10 (每隔1秒监控一次,一共做10次) $ jstat -gc 2840 2000 20 (每隔2秒监控一次,共20次) $ jstat -gcutil 2840 1000 10 (统计gc时,heap情况,按百分比显式) $ jstat -gccause 2840 1000 10 (统计gc的情况,(同-gcutil)和引起gc的事件,按百分比显式) $ jstat -compiler 2840 (显示VM实时编译的数量等信息) $ jstat -gccapacity 25917 (显示,VM内存中三代(young,old,perm)对象的使用和占用大小) $ jstat -gcnew 25917(统计gc时,新生代的情况,new对象的信息) $ jstat -gcnewcapacity 25917 (统计gc时,新生代heap容量 ,new对象的信息及其占用量) $ jstat -gcold 25917 (统计gc时,老年区的情况,old对象的信息) $ jstat -gcoldcapacity 25917 (统计gc时,老年区heap容量,old对象的信息及其占用量) $ jstat -gcpermcapacity 25917 (统计gc时,permanent区heap容量,perm对象的信息及其占用量) $ jstat -printcompilation -h3 25917 1000 5 (当前VM执行的信息,每1000毫秒打印一次,一共打印5次,还可以加上-h3每三行显示一下标题) 一些术语的中文解释: S0C:年轻代中第一个survivor(幸存区)的容量 (字节) S1C:年轻代中第二个survivor(幸存区)的容量 (字节) S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节) S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节) EC:年轻代中Eden(伊甸园)的容量 (字节) EU:年轻代中Eden(伊甸园)目前已使用空间 (字节) OC:Old代的容量 (字节) OU:Old代目前已使用空间 (字节) PC:Perm(持久代)的容量 (字节) PU:Perm(持久代)目前已使用空间 (字节) YGC:从应用程序启动到采样时年轻代中gc次数 YGCT:从应用程序启动到采样时年轻代中gc所用时间(s) FGC:从应用程序启动到采样时old代(全gc)gc次数 FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s) GCT:从应用程序启动到采样时gc用的总时间(s) NGCMN:年轻代(young)中初始化(最小)的大小 (字节) NGCMX:年轻代(young)的最大容量 (字节) NGC:年轻代(young)中当前的容量 (字节) OGCMN:old代中初始化(最小)的大小 (字节) OGCMX:old代的最大容量 (字节) OGC:old代当前新生成的容量 (字节) PGCMN:perm代中初始化(最小)的大小 (字节) PGCMX:perm代的最大容量 (字节) PGC:perm代当前新生成的容量 (字节) S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比 S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比 E:年轻代中Eden(伊甸园)已使用的占当前容量百分比 O:old代已使用的占当前容量百分比 P:perm代已使用的占当前容量百分比 S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节) S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节) ECMX:年轻代中Eden(伊甸园)的最大容量 (字节) DSS:当前需要survivor(幸存区)的容量 (字节)(Eden区已满) TT: 持有次数限制 MTT : 最大持有次数限制 jmap jmap -dump:format=b,file=dump.bin pid jmap 可以从core文件或进程中获得内存的具体匹配情况,包括Heap size, Perm size等等,目前只有在Solaris和Linux的JDK版本里面才有。 观察运行中的jvm物理内存的占用情况打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其数量)。可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本。使用方法 jmap -histo pid。如果连用SHELL jmap -histo pid>a.log可以将其保存到文本中去,在一段时间后,使用文本对比工具,可以对比出GC回收了哪些对象。jmap -dump:format=b,file=String 3024可以将3024进程的内存heap输出出来到String文件里。如果带上live则只统计活对象. $ jmap -histo:live 2840 还有一个很常用的情况是:用jmap把进程内存使用情况dump到文件中,可以用MAT、VisualVM等工具查看,这里用jhat查看分析 jmap -dump:format=b,file=/tmp/dump.dat 21711 dump出来的文件可以用MAT、VisualVM等工具查看,这里用jhat查看 jhat -port 9998 /tmp/dump.dat 然后就可以在浏览器中输入主机地址:9998查看了 jinfo 可以输出并修改运行时的java 进程的opts。 如: 查看运行时的参数 jinfo -flags 2840 查看2788的MaxPerm大小可以用 jinfo -flag MaxPermSize 2788。 参考范例 JAVA_OPTS="-server -Xms4g -Xmx4g -XX:PermSize=96m -XX:MaxPermSize=256m -Xmn2560m -XX:SurvivorRatio=10 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX :CMSMaxAbortablePrecleanTime=5000 -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=80 jstatd 1.启动RMI服务 在需要被监控的服务器上面,通过jstatd来启动RMI服务 首先,配置java安全访问,在服务器jdk路径(/java_home/bin)下新建文件 名称: jstatd.all.policy 内容: grant codebase “file:${java.home}/../lib/tools.jar” { permission java.security.AllPermission; }; 2.然后在进入jstatd.all.policy所在目录下,通过如下的命令启动RMI服务: ./jstatd -J-Djava.security.policy=jstatd.all.policy 或者 ./jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.22.249 jdb jdb用来对core文件和正在运行的Java进程进行实时地调试,里面包含了丰富的命令帮助您进行调试,它的功能和Sun studio里面所带的dbx非常相似,但 jdb是专门用来针对Java应用程序的。用来对core文件和正在运行的Java进程进行实时地调试,里面包含了丰富的命令帮助您进行调试,它的功能和Sun studio里面所带的dbx非常相似,但 jdb是专门用来针对Java应用程序的。 readOnly mode: $ jdb -connect sun.jvm.hotspot.jdi.SAPIDAttachingConnector:pid=9302 debug mode: server add : -Dcom.sun.management.jmxremote.port=50199 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Xrunjdwp:transport=dt_socket,address=50100,server=y,suspend=y client: $jdb -attach 50100 threads thread <thread_id> suspend <thread_id> step (等待) kill <thread_id> new java.lang.Exception() $ jdb -connect sun.jvm.hotspot.jdi.SACoreAttachingConnector:javaExecutable=$JAVA_HOME/bin/java,core=core.20441 $ jdb -connect sun.jvm.hotspot.jdi.SADebugServerAttachingConnector:debugServerName=machine1 ----------------------------- jconsole jconsole是基于 (JMX)的实时图形化监测工具,这个工具利用了内建到JVM里面的JMX指令来提供实时的性能和资源的监控,包括了Java程序的内存使用,Heap size, 线程的状态,类的分配状态和空间使用等等。 与jstat相当。jconsole:一个java GUI监视工具,可以以图表化的形式显示各种数据。并可通过远程连接监视远程的服务器VM。用java写的GUI程序,用来监控VM,并可监控远程的VM,非常易用,而且功能非常强。命令行里打 jconsole,选则进程就可以了