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的用法

java代码造成jvm需要调优_堆栈

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

java代码造成jvm需要调优_堆栈_02

  • Loaded : 加载class的数量
  • Bytes : class字节大小
  • Unloaded : 未加载class的数量
  • Bytes : 未加载class的字节大小
  • Time : 加载时间

-compiler:用来查看即时编译器编译相关信息的统计

java代码造成jvm需要调优_java代码造成jvm需要调优_03

  • Compiled : 编译数量
  • Failed : 编译失败数量
  • Invalid : 无效数量
  • Time : 编译耗时
  • FailedType : 失败类型
  • FailedMethod : 失败方法的全限定名

-gc:用来查看JVM中垃圾收集情况的统计信息,包括Eden区,2个Survivor区域,老年代永久代的容量和已用空间,GC时间

java代码造成jvm需要调优_java代码造成jvm需要调优_04

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:用来查看新生代、老年代和永久代的存储容量

java代码造成jvm需要调优_堆栈_05

  • NGCMN : 新生代占用的最小空间
  • NGCMX : 新生代占用的最大空间
  • OGCMN : 老年代占用的最小空间
  • OGCMX : 老年代占用的最大空间
  • OGC:当前年老代的容量 (KB)
  • OC:当前年老代的空间 (KB)
  • PGCMN : perm占用的最小空间
  • PGCMX : perm占用的最大空间

-gcutil:用来查看新生代、老年代和持久化的垃圾收集情况

java代码造成jvm需要调优_jvm_06

  • S0:幸存1区当前使用比例
  • S1:幸存2区当前使用比例
  • E:伊甸园区使用比例
  • O:老年代使用比例
  • M:元数据区使用比例
  • CCS:压缩使用比例
  • YGC:年轻代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

-gccause:用来查看垃圾收集的统计情况,并且显示最后一次及当前正在发生的垃圾收集的原因

java代码造成jvm需要调优_java_07

  • LGCC:最近垃圾回收的原因
  • GCC:当前垃圾回收的原因

-gcnew:用来查看新生代垃圾收集情况

java代码造成jvm需要调优_java_08

  • S0C:第一个幸存区大小
  • S1C:第二个幸存区的大小
  • S0U:第一个幸存区的使用大小
  • S1U:第二个幸存区的使用大小
  • TT:对象在新生代存活的次数
  • MTT:对象在新生代存活的最大次数
  • DSS:期望的幸存区大小
  • EC:伊甸园区的大小
  • EU:伊甸园区的使用大小
  • YGC:年轻代垃圾回收次数
  • YGCT:年轻代垃圾回收消耗时间

-gcnewcapacity:用来查看新生代存储容量的情况

java代码造成jvm需要调优_老年代_09

  • NGCMN:新生代最小容量
  • NGCMX:新生代最大容量
  • NGC:当前新生代容量
  • S0CMX:最大幸存1区大小
  • S0C:当前幸存1区大小
  • S1CMX:最大幸存2区大小
  • S1C:当前幸存2区大小
  • ECMX:最大伊甸园区大小
  • EC:当前伊甸园区大小
  • YGC:年轻代垃圾回收次数
  • FGC:老年代回收次数

-gcold:用来查看老年代和持久代发生的GC情况

java代码造成jvm需要调优_老年代_10

  • MC:方法区大小
  • MU:方法区使用大小
  • CCSC:压缩类空间大小
  • CCSU:压缩类空间使用大小
  • OC:老年代大小
  • OU:老年代使用大小
  • YGC:年轻代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

-gcoldcapacity:用来查看老年代的容量

java代码造成jvm需要调优_jvm_11

  • OGCMN:老年代最小容量
  • OGCMX:老年代最大容量
  • OGC:当前老年代大小
  • OC:老年代大小
  • YGC:年轻代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

-gcmetacapacity:用来查看持久代的容量

java代码造成jvm需要调优_java_12

  • MCMN:最小元数据容量
  • MCMX:最大元数据容量
  • MC:当前元数据空间大小
  • CCSMN:最小压缩类空间大小
  • CCSMX:最大压缩类空间大小
  • CCSC:当前压缩类空间大小
  • YGC:年轻代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

-printcompilation:用来查看通过JIT编译过的方法

java代码造成jvm需要调优_jvm_13

  • 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