JVM常用工具
- 1. jps
- 1.1 jps的用法
- 1.2 jps命令的一些选项
- 2. jstat
- 2.1 jstat命令的一些选项
- 2.2 常用的方法
- 3. jinfo
- 3.1 常用参数
- 4. jstack
- 4.1 常用参数
- 4.2 案例
- 5. jmap
- 5.1 常用参数
- 5.2 案例
本博客内容参考:《大型分布式网站架构设计与实现》
JDK自身提供了一系列的Java故障排查工具,虽然简单,但是进行在线故障排查时却十分有用;
1. jps
jps命令用来输出JVM虚拟机进程的一些信息,有点类似于Linux的ps命令,可以列出虚拟机当前正在执行的进程,并显示其主类和进程的ID
1.1 jps的用法
1.2 jps命令的一些选项
- -q:只输出进程ID的名称,而省略主类的名称;
- -m:输出进程启动时传递给main函数的参数;
- -l:输出主类的全名,如果执行的是jar文件,则输出jar文件的路径;
- -v:输出虚拟机进程启动时所带的JVM参数;
2. jstat
jstat是一个可以用来对虚拟机各种运行状态进行监控的工具,通过它可以查看到虚拟机的类加载与卸载情况,管理内存使用和垃圾收集等信息,监视JIT即时编译器的运行情况等,几乎包括了JVM运行的方方面面;
2.1 jstat命令的一些选项
- -class:用来查看类加载的统计信息;
- -compiler:用来查看即时编译器编译相关信息的统计;
- -gc:用来查看JVM中垃圾收集情况的统计信息,包括Eden区,2个Survivor区域,老年代永久代的容量和已用空间,GC时间;
- -gccapacity:用来查看新生代、老年代和永久代的存储容量;
- -gcutil:用来查看新生代、老年代和持久化的垃圾收集情况;
- -gccause:用来查看垃圾收集的统计情况,并且显示最后一次及当前正在发生的垃圾收集的原因;
- -gcnew:用来查看新生代垃圾收集情况;
- -gcnewcapacity:用来查看新生代存储容量的情况;
- -gcold:用来查看老年代和持久代发生的GC情况;
- -gcoldcapacity:用来查看老年代的容量;
- -gcmetacapacity :用来查看永生代的容量;
- -printcompilation:用来查看通过JIT编译过的方法;
2.2 常用的方法
这些命令都有一些非常好用的功能:
比如:jstat -gc 1234 1000 10
1000:表示1秒输出一次;
10:表示总共输出10次;
也可以这样用:jstat -gc 1234 1000 10 >> test.log
-class:用来查看类加载的统计信息
通过jps -l 查出需要查看的pid
- Loaded : 加载class的数量
- Bytes : class字节大小
- Unloaded : 未加载class的数量
- Bytes : 未加载class的字节大小
- Time : 加载时间
-compiler:用来查看即时编译器编译相关信息的统计
- Compiled : 编译数量
- Failed : 编译失败数量
- Invalid : 无效数量
- Time : 编译耗时
- FailedType : 失败类型
- FailedMethod : 失败方法的全限定名
-gc:用来查看JVM中垃圾收集情况的统计信息,包括Eden区,2个Survivor区域,老年代永久代的容量和已用空间,GC时间
C即Capacity 总容量,U即Used 已使用的容量
- S0C : survivor0区的总容量
- S1C : survivor1区的总容量
- S0U : survivor0区已使用的容量
- S1U : survivor1区已使用的容量
- EC : Eden区的总容量
- EU : Eden区已使用的容量
- OC : Old区的总容量
- OU : Old区已使用的容量
- PC 当前perm的容量 (KB)
- PU perm的使用 (KB)
- YGC : 新生代垃圾回收次数
- YGCT : 新生代垃圾回收时间
- FGC : 老年代垃圾回收次数
- FGCT : 老年代垃圾回收时间
- GCT : 垃圾回收总消耗时间
-gccapacity:用来查看新生代、老年代和永久代的存储容量
- NGCMN : 新生代占用的最小空间
- NGCMX : 新生代占用的最大空间
- OGCMN : 老年代占用的最小空间
- OGCMX : 老年代占用的最大空间
- OGC:当前年老代的容量 (KB)
- OC:当前年老代的空间 (KB)
- PGCMN : perm占用的最小空间
- PGCMX : perm占用的最大空间
-gcutil:用来查看新生代、老年代和持久化的垃圾收集情况
- S0:幸存1区当前使用比例
- S1:幸存2区当前使用比例
- E:伊甸园区使用比例
- O:老年代使用比例
- M:元数据区使用比例
- CCS:压缩使用比例
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
-gccause:用来查看垃圾收集的统计情况,并且显示最后一次及当前正在发生的垃圾收集的原因
- LGCC:最近垃圾回收的原因
- GCC:当前垃圾回收的原因
-gcnew:用来查看新生代垃圾收集情况
- S0C:第一个幸存区大小
- S1C:第二个幸存区的大小
- S0U:第一个幸存区的使用大小
- S1U:第二个幸存区的使用大小
- TT:对象在新生代存活的次数
- MTT:对象在新生代存活的最大次数
- DSS:期望的幸存区大小
- EC:伊甸园区的大小
- EU:伊甸园区的使用大小
- YGC:年轻代垃圾回收次数
- YGCT:年轻代垃圾回收消耗时间
-gcnewcapacity:用来查看新生代存储容量的情况
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:当前新生代容量
- S0CMX:最大幸存1区大小
- S0C:当前幸存1区大小
- S1CMX:最大幸存2区大小
- S1C:当前幸存2区大小
- ECMX:最大伊甸园区大小
- EC:当前伊甸园区大小
- YGC:年轻代垃圾回收次数
- FGC:老年代回收次数
-gcold:用来查看老年代和持久代发生的GC情况
- MC:方法区大小
- MU:方法区使用大小
- CCSC:压缩类空间大小
- CCSU:压缩类空间使用大小
- OC:老年代大小
- OU:老年代使用大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
-gcoldcapacity:用来查看老年代的容量
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:当前老年代大小
- OC:老年代大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
-gcmetacapacity:用来查看持久代的容量
- MCMN:最小元数据容量
- MCMX:最大元数据容量
- MC:当前元数据空间大小
- CCSMN:最小压缩类空间大小
- CCSMX:最大压缩类空间大小
- CCSC:当前压缩类空间大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
-printcompilation:用来查看通过JIT编译过的方法
- Compiled:被执行的编译任务的数量
- Size:方法字节码的字节数
- Type:编译类型
- Method:编译方法的类名和方法名。
3. jinfo
jinfo命令主要用于查看应用程序的配置参数,以及打印运行JVM时所指定的JVM参数;
-flag : 输出指定args参数的值
-flags : 不需要args参数,输出所有JVM参数的值
-sysprops : 输出系统属性,等同于System.getProperties()
3.1 常用参数
-sysprops:显示System.getProperties()相关参数,还可以显示未被指定的JVM参数的默认值;
4. jstack
jstack命令用来生成虚拟机当前的线程快照信息,线程快照就是当前虚拟机每一个线程正在执行的方法堆栈的集合;
4.1 常用参数
-F : 当正常输出请求不被响应时,强制输出线程堆栈
-l : 除堆栈外,显示关于锁的附加信息
-m : 如果调用到本地方法的话,可以显示C/C++的堆栈
4.2 案例
jstack -l 13352
2020-06-20 22:14:16
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.25-b02 mixed mode):
"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x0000000002c1c800 nid=0x4b08 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"线程B:" #12 prio=5 os_prio=0 tid=0x0000000019567000 nid=0x1354 waiting for monitor entry [0x000000001a3ef000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.demo.jvm.Lock2.run(JconsoleTest.java:44)
- waiting to lock <0x00000000d60b7028> (a java.lang.String)
- locked <0x00000000d60b7060> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"线程A:" #11 prio=5 os_prio=0 tid=0x0000000019566000 nid=0x52fc waiting for monitor entry [0x000000001a2ef000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.demo.jvm.Lock1.run(JconsoleTest.java:26)
- waiting to lock <0x00000000d60b7060> (a java.lang.String)
- locked <0x00000000d60b7028> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"Service Thread" #10 daemon prio=9 os_prio=0 tid=0x0000000019497000 nid=0x4f0c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C1 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x0000000019403000 nid=0x29ac waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x0000000019401000 nid=0x4bb8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x0000000019400800 nid=0x6f4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x00000000191e5000 nid=0x1a3c runnable [0x0000000019cef000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:150)
at java.net.SocketInputStream.read(SocketInputStream.java:121)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x00000000d5fa79f8> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x00000000d5fa79f8> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)
Locked ownable synchronizers:
- None
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000018e33000 nid=0x2a40 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000018e32800 nid=0x4c0c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000000002f03800 nid=0x1544 in Object.wait() [0x0000000018def000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5b86280> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:142)
- locked <0x00000000d5b86280> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:158)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
Locked ownable synchronizers:
- None
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000002efe000 nid=0x2fcc in Object.wait() [0x0000000018cef000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5b85cf0> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:157)
- locked <0x00000000d5b85cf0> (a java.lang.ref.Reference$Lock)
Locked ownable synchronizers:
- None
"VM Thread" os_prio=2 tid=0x0000000017a55000 nid=0x860 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002e2b800 nid=0x1a8 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002e2d000 nid=0x5260 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000000002e2e800 nid=0x16b0 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000000002e30000 nid=0x3e4c runnable
"VM Periodic Task Thread" os_prio=2 tid=0x000000001949a800 nid=0x4eb0 waiting on condition
JNI global references: 34
Found one Java-level deadlock:
=============================
"线程B:":
waiting to lock monitor 0x0000000017a5bd18 (object 0x00000000d60b7028, a java.lang.String),
which is held by "线程A:"
"线程A:":
waiting to lock monitor 0x0000000017a5e708 (object 0x00000000d60b7060, a java.lang.String),
which is held by "线程B:"
Java stack information for the threads listed above:
===================================================
"线程B:":
at com.example.demo.jvm.Lock2.run(JconsoleTest.java:44)
- waiting to lock <0x00000000d60b7028> (a java.lang.String)
- locked <0x00000000d60b7060> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
"线程A:":
at com.example.demo.jvm.Lock1.run(JconsoleTest.java:26)
- waiting to lock <0x00000000d60b7060> (a java.lang.String)
- locked <0x00000000d60b7028> (a java.lang.String)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
可以看出,上面的案例,有死锁发生;
5. jmap
jmap可以用来查看等待回收对象的队列,查看堆的概要信息,包括采用的是哪种GC收集器,堆空间的使用情况,以及通过JVM参数指定的各个内存空间的大小等;
jmap执行堆dump操作时,由于生成的转储文件较大,将耗费大量的系统资源,可能会造成短时间内系统无法响应的情况出现;
5.1 常用参数
- dump:[live,]format=b,file= : 生成堆转储快照
- finalizerinfo : 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
- heap : 用来打印堆的概要信息,包括使用回收器的类型,堆的配置信息,各内存分代的空间使用情况;
- histo[:live] : 显示堆中对象的统计信息
- permstat : 用来打印出每个ClassLoader和该ClassLoader所加载的class数量;
- F : 当-dump没有响应时,强制生成dump快照
5.2 案例
-heap:用来打印堆的概要信息
jmap -heap 13352
using thread-local object allocation.
Parallel GC with 4 thread(s) // GC方式
Heap Configuration: //堆内存初始化配置
MinHeapFreeRatio = 0 //-XX:MinHeapFreeRatio设置JVM堆最小空闲比率
MaxHeapFreeRatio = 100 //-XX:MaxHeapFreeRatio设置JVM堆最大空闲比率
MaxHeapSize = 2132803584 (2034.0MB) //-XX:MaxHeapSize=设置JVM堆的最大大小
NewSize = 44564480 (42.5MB) //-XX:NewSize=设置JVM堆的'新生代'的默认(起始)大小
MaxNewSize = 710934528 (678.0MB) //-XX:MaxNewSize=设置JVM堆的'新生代'的最大大小
OldSize = 89653248 (85.5MB) //-XX:OldSize=设置JVM堆的'老年代'的大小
NewRatio = 2 //-XX:NewRatio=:'新生代'和'老年代'的大小比率1:2
SurvivorRatio = 8 //-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值8:1:1
MetaspaceSize = 21807104 (20.796875MB)//-XX:MaxPermSize=256m 设置元空间大小
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB // -XX:MaxMetaspaceSize= :设置JVM堆的‘元空间’的最大大小
G1HeapRegionSize = 0 (0.0MB)
Heap Usage: //堆内存使用情况
PS Young Generation //新生代
Eden Space: //Eden区分布
capacity = 176160768 (168.0MB) //总空间
used = 6222416 (5.9341583251953125MB) //已用空间
free = 169938352 (162.0658416748047MB) //空闲空间
3.532237098330543% used //使用比率
From Space: //survivor From区分布
capacity = 16777216 (16.0MB)
used = 0 (0.0MB)
free = 16777216 (16.0MB)
0.0% used
To Space: //survivor To区分布
capacity = 17301504 (16.5MB)
used = 0 (0.0MB)
free = 17301504 (16.5MB)
0.0% used
PS Old Generation //老年代分布
capacity = 164626432 (157.0MB)
used = 17516744 (16.70526885986328MB)
free = 147109688 (140.29473114013672MB)
10.640298636855594% used
-dump:生成堆快照
jmap -dump:live,format=b,file=dump.hprof 13352