Java应用程序在运行的时候可能会出现莫名的卡顿,CPU使用率很高等情况,这个时候我们需要定位问题,就需要使用到JVM的一些命令和工具。下面总结了我们在排查问题的时候经常使用的命令和工具(基于JDK1.8)。
常用命令
jstack
1 | Usage: |
官方文档
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstack.html
打印线程栈日志(-l 表示打印出关于锁的额外信息)
jstack -l pid
jinfo
1 | Usage: |
官方文档
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html#BCGEBFDD
查看某个Java进程设置的最大堆内存
jinfo -flag MaxHeapSize pid
-XX:MaxHeapSize=482344960(字节)
查看某个Java进程设置的所有参数
jinfo -flags pid
查看Java系统属性
Jinfo -sysprops pid
= 表示默认值
:= 被用户或者JVM修改后的值
比如:
bool UseG1GC = false // =表示默认值
uintx MaxNewSize := 160759808 // :=表示被用户或jvm修改后的值
Non-default VM flags: 被手动赋值的参数,有的是自己设的(比如使用jinfo命令动态设置参数),有的是tomcat的shell脚本里tomcat设置的
jmap
1 | Usage: |
官方文档
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html#CEGCECJB
查看某个Java进程的内存映像信息
jmap pid
1 | Attaching to process ID 32325, please wait... |
使用不带选项参数的jmap打印共享对象映射,将会打印目标虚拟机中加载的每个共享对象的起始地址、映射大小以及共享对象文件的路径全称。
显示Java堆详细信息
jmap -heap pid
打印一个堆的摘要信息,包括使用的GC算法、堆配置信息和各内存区域内存使用信息。
1 | Attaching to process ID 32325, please wait... |
显示堆中对象的统计信息
jmap -histo:live pid
其中包括每个Java类、对象数量、内存大小(单位:字节)、完全限定的类名。打印的虚拟机内部的类名称将会带有一个’*’前缀。如果指定了live子选项,则只计算活动的对象。
打印等待回收的对象信息
jmap -finalizeerinfo pid
Number of objects pending for finalization: 0 说明当前F-QUEUE队列中并没有等待Fializer线程执行finalizer方法。
生成堆转储快照
jmap -dump:format=b,file=heapdump.phrof pid
以hprof二进制格式转储Java堆到指定filename的文件中。live子选项是可选的。如果指定了live子选项,堆中只有活动的对象会被转储。想要浏览heap dump,你可以使用jhat(Java堆分析工具), jvisualvm, mat读取生成的文件。这个命令在线上慎用,如果heap比较大的话,就会导致dump比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用,线上系统慎用。
jstat
1 | Usage: jstat -help|-options |
官方文档
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html#BEHHGFAE
显示加载 class 的数量,以及所占空间等信息。
jstat -class pid
Loaded : 加载class的数量
Bytes : class字节大小
Unloaded : 卸载class的数量
Bytes : 卸载class的字节大小
Time : 加载时间
显示JVM实时编译(JIT)的数量等信息
jstat -compiler pid
Compiled : 编译数量
Failed : 编译失败数量
Invalid : 无效数量
Time : 编译耗时
FailedType : 失败类型
FailedMethod : 失败方法的全限定名
查看gc次数,以及时间
jstat -gc pid
1 | S1C:年轻代中第二个survivor(幸存区)的容量 (KB) |
查看JVM内存中对象的使用情况和占用空间大小
jstat -gccapacity pid
1 | NGCMN :年轻代(young)中初始化(最小)的大小(KB) |
元空间(Metaspace)中对象的信息及其占用空间。
jstat -gcmetacapacity pid
1 | MCMN:最小元数据容量 |
新生代对象相关信息。
jstat -gcnew pid
1 | S0C :年轻代中第一个survivor(幸存区)的容量 (KB) |
新生代对象的信息以及占用空间
jstat -gcnewcapacity pid
1 | NGCMN :年轻代(young)中初始化(最小)的大小(KB) |
老年代对象的信息
jstat -gcold pid
1 | MC :metaspace(元空间)的容量 (KB) |
老年代对象信息及其占用空间
jstat -gcoldcapacity pid
1 | OGCMN :old代中初始化(最小)的大小 (KB) |
统计gc信息
jstat -gcutil pid
jstat -gcutil pid 1000 10 每1s打印一次gc信息,总共打印10次
1 | S0 :年轻代中第一个survivor(幸存区)已使用的占当前容量百分比 |
显示垃圾回收的相关信息,同时显示最后一次或当前正在发生的垃圾回收的诱因。
jstat -gccause pid
1 | LGCC:最后一次GC原因 |
当前jvm执行的信息。
jstat -printcompilation pid
1 | Compiled :编译任务的数目 |
jhat
1 | Usage: jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [-debug <int>] [-version] [-h|-help] <file> |
官方文档
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jhat.html#CIHHJAGE
jhat是用来分析jmap生成dump文件的命令,jhat内置了应用服务器,可以通过网页查看dump文件分析结果,jhat一般是用在离线分析上。
jhat dump.hprof
访问localhost:7000,所看到的页面如下图所示:
jconsole,jvisualvm
除了可以使用jhat来分析堆dump文件,也可以使用jconsole,或者jvisualvm来分析。
jconslole官方文档
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jconsole.html#CACCABEH
jvisualvm官方文档
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jvisualvm.html#CBBEGDEJ
分析堆dump文件
CPU占用率高:
其它命令
查看JVM所有可设置参数及其值
java -XX:+PrintFlagsFinal -version
命令实战
jstack 分析死锁,死循环,CPU高占用率
jps -l 获取对应的Java进程的pid。
查看该进程对应的线程状态,输入大写的P即可按照CPU的使用率降序排列。
top -Hp pid
找到CPU使用率最高的线程id,然后把线程id转换为16进制的。
Printf “%x\n”
下面可以通过获取到的线程id来查看栈信息。
Jstack -l pid | grep -30 ‘<16进制的thread id>’
重点关注一下状态的线程。
1 | 1) 死锁, Deadlock (重点关注) |