Loading...
墨滴

楼仔

2021/09/13  阅读:42  主题:橙心

【JVM系列4】JVM常用命令

讲解JVM的常用命令,为后面讲解JVM日志分析做准备。

前言

JVM比较重要的知识,在前面三篇文章都将完了,GC日志在第一篇文章中也有所提及,这篇文章主要讲解JVM常用的命令,虽然jvm调优成熟的工具已经有很多,但是所有的工具几乎都是依赖于jdk的接口和底层的这些命令,研究这些命令的使用也让我们更能了解jvm构成和特性。

Sun JDK监控和故障处理命令有jps、jstat、jmap、jhat、jstack、jinfo,下面做一一介绍。

jps

JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。

命令格式:

jps [options] [hostid]

option参数:

  • -l : 输出主类全名或jar路径
  • -q : 只输出LVMID
  • -m : 输出JVM启动时传递给main()的参数
  • -v : 输出JVM启动时显示指定的JVM参数

示例:

82518 sun.tools.jps.Jps -l -m
69981 /Users/mengloulv/Library/Application Support/JetBrains/IntelliJIdea2020.1/plugins/idea-spring-tools/lib/server/language-server.jar
79213 org.apache.catalina.startup.Bootstrap start
79212 org.jetbrains.jps.cmdline.Launcher /Applications/IntelliJ IDEA.app/Contents/lib/asm-all-7.0.1.jar:xxx...

jstat

jstat(JVM statistics Monitoring)是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。

详见:https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html#gcnew_option

jstat介绍

jstat命令命令格式:
jstat [Options] vmid [interval] [count]
 
命令参数说明:
Options,一般使用 -gcutil 或  -gc 查看gc 情况
pid,当前运行的 java进程号 
interval,间隔时间,单位为秒或者毫秒 
count,打印次数,如果缺省则打印无数次
 
Options 参数如下:
-gc:统计 jdk gc时 heap信息,以使用空间字节数表示
-gcutil:统计 gc时, heap情况,以使用空间的百分比表示
-class:统计 class loader行为信息
-compile:统计编译行为信息
-gccapacity:统计不同 generations(新生代,老年代,持久代)的 heap容量情况
-gccause:统计引起 gc的事件
-gcnew:统计 gc时,新生代的情况
-gcnewcapacity:统计 gc时,新生代 heap容量
-gcold:统计 gc时,老年代的情况
-gcoldcapacity:统计 gc时,老年代 heap容量
-gcpermcapacity:统计 gc时, permanent区 heap容量

jstat使用示例

示例 1:jstat -gc 15 5000 5

每5秒一次显示进程号为15的java进程的GC情况,每5S生成异常,一共生成5次。

 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
307200.0 307200.0 24333.5  0.0   2457600.0 945456.5 5120000.0  3462367.2  241360.0 209218.1 26120.0 20538.3   6642  531.164  20      6.874  538.038
307200.0 307200.0 24333.5  0.0   2457600.0 945513.4 5120000.0  3462367.2  241360.0 209218.1 26120.0 20538.3   6642  531.164  20      6.874  538.038
307200.0 307200.0 24333.5  0.0   2457600.0 968130.4 5120000.0  3462367.2  241360.0 209218.1 26120.0 20538.3   6642  531.164  20      6.874  538.038
307200.0 307200.0 24333.5  0.0   2457600.0 1394418.3 5120000.0  3462367.2  241360.0 209218.1 26120.0 20538.3   6642  531.164  20      6.874  538.038
307200.0 307200.0 24333.5  0.0   2457600.0 1867238.5 5120000.0  3462367.2  241360.0 209218.1 26120.0 20538.3   6642  531.164  20      6.874  538.038
S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
OC:老年代大小
OU:老年代使用大小
MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
单位:KB

我可以计算出如下核心数据:

  • 第一个幸存区的大小S0C:300M
  • 第二个幸存区的大小S1C:300M
  • 伊甸园区的大小EC:2400M
  • 老年代大小OC:5000M
  • 方法区大小MC:236M
  • 年轻代垃圾回收消耗时间YGCT:531.164(单位?)
  • 老年代垃圾回收消耗时间FGCT:6.874(单位?)

我们再看输出的GC日志:

Heap before GC invocations=6641 (full 10):
 par new generation   total 2764800K, used 2492979K [0x00000005cc000000, 0x0000000687800000, 0x0000000687800000)
  eden space 2457600K, 100% used [0x00000005cc000000, 0x0000000662000000, 0x0000000662000000)
  from space 307200K,  11% used [0x0000000674c00000, 0x0000000676e8cc90, 0x0000000687800000)
  to   space 307200K,   0% used [0x0000000662000000, 0x0000000662000000, 0x0000000674c00000)
 concurrent mark-sweep generation total 5120000K, used 3462278K [0x0000000687800000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 209218K, capacity 229352K, committed 241360K, reserved 1265664K
  class space    used 20538K, capacity 24038K, committed 26120K, reserved 1048576K
343501.719: [GC (Allocation Failure) 343501.719: [ParNew: 2492979K->24333K(2764800K), 0.0261186 secs] 5955257K->3486700K(7884800K), 0.0262698 secs] [Times: user=0.05 sys=0.01, real=0.03 secs]

可以计算出如下核心数据:

  • 第一个幸存区的大小S0C:300M
  • 第二个幸存区的大小S1C:300M
  • 伊甸园区的大小EC:2400M
  • 老年代大小OC:从这里计算不出来
  • 方法区大小MC:从这里计算不出来
  • GC耗时:30ms

我配置的JAVA_OPTS参数如下:

-Xmx8000M -Xms8000M -Xmn3000M -XX:PermSize=1000M -XX:MaxPermSize=1000M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=69 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:/home/work/logs/applogs/gc.log -javaagent:/home/work/app/prometheus/jmx_prometheus_javaagent-0.12.0.jar=3010:/home/work/app/prometheus/jmx-exporter.yml

这里我有两个疑问:

  • 疑问1:其中2764800/1024=2700M,这个2700M是什么呢?是EC+S0C,或者是EC+S1C么?即“新生代当前可以使用的容量”么?(因为每次S0C和S1C,只会使用其中一个)
  • 疑问2:其中7884800K/1024=7700M,这个7700M是什么呢?是OC+EC+S0C,或者是EC+S1C么?即老年代 + “新生代当前可以使用的容量”么?

示例2:jstat -gccapacity 15

同-gc,不过还会输出Java堆各区域使用到的最大、最小空间

   NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC 
819200.0 819200.0 819200.0 273024.0 273024.0 273152.0  5324800.0  5324800.0  5324800.0  5324800.0      0.0 1251328.0 223560.0      0.0 1048576.0  22716.0    174     8
NGCMN Minimum new generation capacity (KB).
NGCMX Maximum new generation capacity (KB).
NGC Current new generation capacity (KB).
S0C Current survivor space 0 capacity (KB).
S1C Current survivor space 1 capacity (KB).
EC Current eden space capacity (KB).
OGCMN Minimum old generation capacity (KB).
OGCMX Maximum old generation capacity (KB).
OGC Current old generation capacity (KB).
OC Current old space capacity (KB).
PGCMN Minimum permanent generation capacity (KB).
PGCMX Maximum Permanent generation capacity (KB).
PGC Current Permanent generation capacity (KB).
PC Current Permanent space capacity (KB).
YGC Number of Young generation GC Events.
FGC Number of Full GC Events.

示例3:jstat -gcutil 15

同-gc,不过输出的是已使用空间占总空间的百分比

详见:https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html#gcutil_option

   S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
  0.32   0.00  27.68   9.86  98.17  96.03    174   24.437     8    0.720   25.157

示例4:jstat -gccause 15

垃圾收集统计概述(同-gcutil),附加最近两次垃圾回收事件的原因

详见:https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html#gccause_option

   S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT    LGCC                 GCC                 
  0.32   0.00  43.15   9.86  98.17  96.03    174   24.437     8    0.720   25.157 Allocation Failure   No GC
LGCC:最近垃圾回收的原因
GCC:当前垃圾回收的原因

示例5:jstat -gcnew 15

统计新生代的行为

详见:https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html#gcnew_option

   S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
273024.0 273024.0  862.5    0.0 15  15 136512.0 273152.0 119572.5    174   24.437

示例6:jstat -gcold 15

统计新生代的行为

详见:https://docs.oracle.com/javase/7/docs/technotes/tools/share/jstat.html#gcold_option

   MC       MU      CCSC     CCSU       OC          OU       YGC    FGC    FGCT     GCT   
223560.0 219467.9  22716.0  21813.1   5324800.0    524929.7    174     8    0.720   25.157

示例 7:jstat -class 15

监视类装载、卸载数量、总空间以及耗费的时间。

Loaded  Bytes  Unloaded  Bytes     Time   
 39163 74053.8    11505 17286.0      46.52
Loaded : 加载class的数量
Bytes : class字节大小
Unloaded : 未加载class的数量
Bytes : 未加载class的字节大小
Time : 加载时间

示例8:jstat -compiler 15

输出JIT编译过的方法数量耗时等。

Compiled Failed Invalid   Time   FailedType FailedMethod
   53393      4       0   575.86          1 com/mysql/jdbc/AbandonedConnectionCleanupThread run
Compiled : 编译数量
Failed : 编译失败数量
Invalid : 无效数量
Time : 编译耗时
FailedType : 失败类型
FailedMethod : 失败方法的全限定名

jmap

示例1:jmap -dump:live,format=b,file=dump.hprof 15

dump堆到文件,format指定输出格式,live指明是活着的对象,file指定文件名

Dumping heap to /Users/mengloulv/java-workspace/dump.hprof ...
Heap dump file created

dump.hprof这个后缀是为了后续可以直接用MAT(Memory Anlysis Tool)打开。

示例2:jmap -finalizerinfo 15

打印等待回收对象的信息

Attaching to process ID 15, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08
Number of objects pending for finalization: 0

可以看到当前F-QUEUE队列中并没有等待Finalizer线程执行finalizer方法的对象

示例3:jmap -heap 15

打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情况,可以用此来判断内存目前的使用情况以及垃圾回收情况,感觉这个非常使用!

Attaching to process ID 15, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.202-b08

using parallel threads in the new generation.
using thread-local object allocation. //GC 方式  
Concurrent Mark-Sweep GC

Heap Configuration: //堆内存初始化配置
   MinHeapFreeRatio         = 40 /对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
   MaxHeapFreeRatio         = 70 //对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
   MaxHeapSize              = 8388608000 (8000.0MB) //对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
   NewSize                  = 3145728000 (3000.0MB) //对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
   MaxNewSize               = 3145728000 (3000.0MB) /对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
   OldSize                  = 5242880000 (5000.0MB) //对应jvm启动参数-XX:OldSize=<value>:设置JVM堆的‘老生代’的大小
   NewRatio                 = 2 //对应jvm启动参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
   SurvivorRatio            = 8 //对应jvm启动参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值 
   MetaspaceSize            = 21807104 (20.796875MB) 
   CompressedClassSpaceSize = 1073741824 (1024.0MB) 
   MaxMetaspaceSize         = 17592186044415 MB //对应jvm启动参数-XX:MaxPermSize=<value>:设置JVM堆的‘永生代’的最大大小
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage: //堆内存使用情况
New Generation (Eden + 1 Survivor Space):
   capacity = 2831155200 (2700.0MB)
   used     = 1819140416 (1734.8674926757812MB)
   free     = 1012014784 (965.1325073242188MB)
   64.2543515805845% used
Eden Space:
   capacity = 2516582400 (2400.0MB)
   used     = 1795637848 (1712.4536972045898MB)
   free     = 720944552 (687.5463027954102MB)
   71.35223738352458% used
From Space:
   capacity = 314572800 (300.0MB)
   used     = 23502568 (22.413795471191406MB)
   free     = 291070232 (277.5862045288086MB)
   7.471265157063802% used
To Space:
   capacity = 314572800 (300.0MB)
   used     = 0 (0.0MB)
   free     = 314572800 (300.0MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 5242880000 (5000.0MB)
   used     = 3448095536 (3288.360153198242MB)
   free     = 1794784464 (1711.6398468017578MB)
   65.76720306396484% used

101426 interned Strings occupying 10749600 bytes.

示例4:jmap -histo:live 15 | more

打印堆的对象统计,包括对象数、内存大小等等 (因为在dump:live前会进行full gc,如果带上live则只统计活对象,因此不加live的堆大小要大于加live堆的大小 ),仅打印前15行。

  num     #instances         #bytes  class name
----------------------------------------------
   1:        938552      113143448  [C
   2:        983711       31478752  java.util.HashMap$Node
   3:        930339       22328136  java.lang.String
   4:         61854       21628224  [B
   5:        215981       19006328  java.lang.reflect.Method
   6:        200183       18164992  [Ljava.lang.Object;
   7:        121341       16297048  [Ljava.util.HashMap$Node;
   8:        511306       12919376  [Ljava.lang.String;
   9:        169168        9391000  [I
  10:        165488        6619520  java.util.LinkedHashMap$Entry
  11:        131563        6315024  org.hibernate.hql.internal.ast.tree.Node
  12:        122202        5865696  java.util.HashMap
  13:        320105        5121680  java.lang.Integer
  14:        204087        4898088  java.util.ArrayList
  15:        138888        4444416  java.util.concurrent.ConcurrentHashMap$Node
  ... ...

xml class name是对象类型,说明如下:

B  byte
C  char
D  double
F  float
I  int
J  long
Z  boolean
[数组,如[I表示int[]
[L+类名 其他对象

jhat

jhat(JVM Heap Analysis Tool)命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看。在此要注意,一般不会直接在服务器上进行分析,因为jhat是一个耗时并且耗费硬件资源的过程,一般把服务器生成的dump文件复制到本地或其他机器上进行分析。

示例:jhat dump.hprof

当执行完毕后:

可以通过Http://localhost:7000访问:

具体排查时需要结合代码,观察是否大量应该被回收的对象在一直被引用或者是否有占用内存特别大的对象无法被回收。一般情况,会down到客户端用工具来分析。

jstack

jstack用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。

另外,jstack工具还可以附属到正在运行的java程序中,看到当时运行的java程序的java stack和native stack的信息, 如果现在运行的java程序呈现hung的状态,jstack是非常有用的。

命令格式:

jstack [option] LVMID

option参数:

-F : 当正常输出请求不被响应时,强制输出线程堆栈
-l : 除堆栈外,显示关于锁的附加信息
-m : 如果调用到本地方法的话,可以显示C/C++的堆栈

示例:jstack -l 5073|more

欢迎大家多多点赞,更多文章,请关注微信公众号“楼仔进阶之路”,点关注,不迷路~~

楼仔

2021/09/13  阅读:42  主题:橙心

作者介绍

楼仔