JVM监控和常用命令

Java应用程序在运行的时候可能会出现莫名的卡顿,CPU使用率很高等情况,这个时候我们需要定位问题,就需要使用到JVM的一些命令和工具。下面总结了我们在排查问题的时候经常使用的命令和工具(基于JDK1.8)。

常用命令

jstack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)

Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message

官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstack.html

  1. 打印线程栈日志(-l 表示打印出关于锁的额外信息)

    jstack -l pid

jinfo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Usage:
jinfo [option] <pid>
(to connect to running process)
jinfo [option] <executable <core>
(to connect to a core file)
jinfo [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)

where <option> is one of:
-flag <name> to print the value of the named VM flag
-flag [+|-]<name> to enable or disable the named VM flag
-flag <name>=<value> to set the named VM flag to the given value
-flags to print VM flags
-sysprops to print Java system properties
<no option> to print both of the above
-h | -help to print this help message

官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jinfo.html#BCGEBFDD

  1. 查看某个Java进程设置的最大堆内存

    jinfo -flag MaxHeapSize pid

    -XX:MaxHeapSize=482344960(字节)

  2. 查看某个Java进程设置的所有参数

    jinfo -flags pid

  3. 查看Java系统属性

    Jinfo -sysprops pid

= 表示默认值

:= 被用户或者JVM修改后的值

比如:

bool UseG1GC = false // =表示默认值

uintx MaxNewSize := 160759808 // :=表示被用户或jvm修改后的值

Non-default VM flags: 被手动赋值的参数,有的是自己设的(比如使用jinfo命令动态设置参数),有的是tomcat的shell脚本里tomcat设置的

jmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Usage:
jmap [option] <pid>
(to connect to running process)
jmap [option] <executable <core>
(to connect to a core file)
jmap [option] [server_id@]<remote server IP or hostname>
(to connect to remote debug server)

where <option> is one of:
<none> to print same info as Solaris pmap
-heap to print java heap summary
-histo[:live] to print histogram of java object heap; if the "live"
suboption is specified, only count live objects
-clstats to print class loader statistics
-finalizerinfo to print information on objects awaiting finalization
-dump:<dump-options> to dump java heap in hprof binary format
dump-options:
live dump only live objects; if not specified,
all objects in the heap are dumped.
format=b binary format
file=<file> dump heap to <file>
Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo
to force a heap dump or histogram when <pid> does not
respond. The "live" suboption is not supported
in this mode.
-h | -help to print this help message
-J<flag> to pass <flag> directly to the runtime system

官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html#CEGCECJB

  1. 查看某个Java进程的内存映像信息

    jmap pid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Attaching to process ID 32325, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
0x0000000000400000 7K /usr/java/jdk/jdk1.8.0_131/bin/java
0x00007f75a11a8000 90K /usr/java/jdk/jdk1.8.0_131/jre/lib/amd64/libnio.so
0x00007f75a13b9000 49K /usr/java/jdk/jdk1.8.0_131/jre/lib/amd64/libmanagement.so
0x00007f75a18c2000 113K /usr/java/jdk/jdk1.8.0_131/jre/lib/amd64/libnet.so
0x00007f75c87f9000 121K /usr/java/jdk/jdk1.8.0_131/jre/lib/amd64/libzip.so
0x00007f75c8a14000 60K /usr/lib64/libnss_files-2.17.so
0x00007f75c8c27000 220K /usr/java/jdk/jdk1.8.0_131/jre/lib/amd64/libjava.so
0x00007f75c8e53000 64K /usr/java/jdk/jdk1.8.0_131/jre/lib/amd64/libverify.so
0x00007f75c9061000 43K /usr/lib64/librt-2.17.so
0x00007f75c9269000 1114K /usr/lib64/libm-2.17.so
0x00007f75c956b000 16597K /usr/java/jdk/jdk1.8.0_131/jre/lib/amd64/server/libjvm.so
0x00007f75ca55e000 2062K /usr/lib64/libc-2.17.so
0x00007f75ca920000 19K /usr/lib64/libdl-2.17.so
0x00007f75cab24000 100K /usr/java/jdk/jdk1.8.0_131/lib/amd64/jli/libjli.so
0x00007f75cad3a000 138K /usr/lib64/libpthread-2.17.so
0x00007f75caf56000 160K /usr/lib64/ld-2.17.so

使用不带选项参数的jmap打印共享对象映射,将会打印目标虚拟机中加载的每个共享对象的起始地址、映射大小以及共享对象文件的路径全称。

  1. 显示Java堆详细信息

    jmap -heap pid

打印一个堆的摘要信息,包括使用的GC算法、堆配置信息和各内存区域内存使用信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
Attaching to process ID 32325, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11

using thread-local object allocation.
Mark Sweep Compact GC

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 482344960 (460.0MB)
NewSize = 10485760 (10.0MB)
MaxNewSize = 160759808 (153.3125MB)
OldSize = 20971520 (20.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 9437184 (9.0MB)
used = 3872032 (3.692657470703125MB)
free = 5565152 (5.307342529296875MB)
41.02952745225694% used
Eden Space:
capacity = 8388608 (8.0MB)
used = 3835424 (3.657745361328125MB)
free = 4553184 (4.342254638671875MB)
45.72181701660156% used
From Space:
capacity = 1048576 (1.0MB)
used = 36608 (0.034912109375MB)
free = 1011968 (0.965087890625MB)
3.4912109375% used
To Space:
capacity = 1048576 (1.0MB)
used = 0 (0.0MB)
free = 1048576 (1.0MB)
0.0% used
tenured generation:
capacity = 20971520 (20.0MB)
used = 7702632 (7.345802307128906MB)
free = 13268888 (12.654197692871094MB)
36.72901153564453% used

4864 interned Strings occupying 496072 bytes.
  1. 显示堆中对象的统计信息

    jmap -histo:live pid

其中包括每个Java类、对象数量、内存大小(单位:字节)、完全限定的类名。打印的虚拟机内部的类名称将会带有一个’*’前缀。如果指定了live子选项,则只计算活动的对象。

  1. 打印等待回收的对象信息

    jmap -finalizeerinfo pid

Number of objects pending for finalization: 0 说明当前F-QUEUE队列中并没有等待Fializer线程执行finalizer方法。

  1. 生成堆转储快照

    jmap -dump:format=b,file=heapdump.phrof pid

以hprof二进制格式转储Java堆到指定filename的文件中。live子选项是可选的。如果指定了live子选项,堆中只有活动的对象会被转储。想要浏览heap dump,你可以使用jhat(Java堆分析工具), jvisualvm, mat读取生成的文件。这个命令在线上慎用,如果heap比较大的话,就会导致dump比较耗时,并且执行的过程中为了保证dump的信息是可靠的,所以会暂停应用,线上系统慎用。

jstat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Usage: jstat -help|-options
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

Definitions:
<option> An option reported by the -options option
<vmid> Virtual Machine Identifier. A vmid takes the following form:
<lvmid>[@<hostname>[:<port>]]
Where <lvmid> is the local vm identifier for the target
Java virtual machine, typically a process id; <hostname> is
the name of the host running the target Java virtual machine;
and <port> is the port number for the rmiregistry on the
target host. See the jvmstat documentation for a more complete
description of the Virtual Machine Identifier.
<lines> Number of samples between header lines.
<interval> Sampling interval. The following forms are allowed:
<n>["ms"|"s"]
Where <n> is an integer and the suffix specifies the units as
milliseconds("ms") or seconds("s"). The default units are "ms".
<count> Number of samples to take before terminating.
-J<flag> Pass <flag> directly to the runtime system.

官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html#BEHHGFAE

  1. 显示加载 class 的数量,以及所占空间等信息。

    jstat -class pid

    • Loaded : 加载class的数量

    • Bytes : class字节大小

    • Unloaded : 卸载class的数量

    • Bytes : 卸载class的字节大小

    • Time : 加载时间

  2. 显示JVM实时编译(JIT)的数量等信息

    jstat -compiler pid

    • Compiled : 编译数量

    • Failed : 编译失败数量

    • Invalid : 无效数量

    • Time : 编译耗时

    • FailedType : 失败类型

    • FailedMethod : 失败方法的全限定名

  3. 查看gc次数,以及时间

    jstat -gc pid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
S1C:年轻代中第二个survivor(幸存区)的容量 (KB)
S0U :年轻代中第一个survivor(幸存区)目前已使用空间 (KB)
S1U :年轻代中第二个survivor(幸存区)目前已使用空间 (KB)
EC :年轻代中Eden(伊甸园)的容量 (KB)
EU :年轻代中Eden(伊甸园)目前已使用空间 (KB)
OC :Old代的容量 (KB)
OU :Old代目前已使用空间 (KB)
MC:metaspace(元空间)的容量 (KB)
MU:metaspace(元空间)目前已使用空间 (KB)
YGC :从应用程序启动到采样时年轻代中gc次数
YGCT :从应用程序启动到采样时年轻代中gc所用时间(s)
FGC :从应用程序启动到采样时old代(全gc)gc次数
FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
  1. 查看JVM内存中对象的使用情况和占用空间大小

    jstat -gccapacity pid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
NGCMN :年轻代(young)中初始化(最小)的大小(KB)
NGCMX :年轻代(young)的最大容量 (KB)
NGC :年轻代(young)中当前的容量 (KB)
S0C :年轻代中第一个survivor(幸存区)的容量 (KB)
S1C : 年轻代中第二个survivor(幸存区)的容量 (KB)
EC :年轻代中Eden(伊甸园)的容量 (KB)
OGCMN :old代中初始化(最小)的大小 (KB)
OGCMX :old代的最大容量(KB)
OGC:old代当前新生成的容量 (KB)
OC :Old代的容量 (KB)
MCMN:metaspace(元空间)中初始化(最小)的大小 (KB)
MCMX :metaspace(元空间)的最大容量 (KB)
MC :metaspace(元空间)当前的容量 (KB)
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC :从应用程序启动到采样时年轻代中gc次数
FGC:从应用程序启动到采样时old代(全gc)gc次数
  1. 元空间(Metaspace)中对象的信息及其占用空间。

    jstat -gcmetacapacity pid

1
2
3
4
5
6
7
8
9
10
MCMN:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC :从应用程序启动到采样时年轻代中gc次数
FGC :从应用程序启动到采样时old代(全gc)gc次数
FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
  1. 新生代对象相关信息。

    jstat -gcnew pid

1
2
3
4
5
6
7
8
9
10
11
S0C :年轻代中第一个survivor(幸存区)的容量 (KB)
S1C :年轻代中第二个survivor(幸存区)的容量 (KB)
S0U :年轻代中第一个survivor(幸存区)目前已使用空间 (KB)
S1U :年轻代中第二个survivor(幸存区)目前已使用空间 (KB)
TT:持有次数限制
MTT:最大持有次数限制
DSS:期望的幸存区大小
EC:年轻代中Eden(伊甸园)的容量 (KB)
EU :年轻代中Eden(伊甸园)目前已使用空间 (KB)
YGC :从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
  1. 新生代对象的信息以及占用空间

    jstat -gcnewcapacity pid

1
2
3
4
5
6
7
8
9
10
11
NGCMN :年轻代(young)中初始化(最小)的大小(KB)
NGCMX :年轻代(young)的最大容量 (KB)
NGC :年轻代(young)中当前的容量 (KB)
S0CMX :年轻代中第一个survivor(幸存区)的最大容量 (KB)
S0C :年轻代中第一个survivor(幸存区)的容量 (KB)
S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (KB)
S1C:年轻代中第二个survivor(幸存区)的容量 (KB)
ECMX:年轻代中Eden(伊甸园)的最大容量 (KB)
EC:年轻代中Eden(伊甸园)的容量 (KB)
YGC:从应用程序启动到采样时年轻代中gc次数
FGC:从应用程序启动到采样时old代(全gc)gc次数
  1. 老年代对象的信息

    jstat -gcold pid

1
2
3
4
5
6
7
8
9
10
MC :metaspace(元空间)的容量 (KB)
MU:metaspace(元空间)目前已使用空间 (KB)
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
OC:Old代的容量 (KB)
OU:Old代目前已使用空间 (KB)
YGC:从应用程序启动到采样时年轻代中gc次数
FGC:从应用程序启动到采样时old代(全gc)gc次数
FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
  1. 老年代对象信息及其占用空间

    jstat -gcoldcapacity pid

1
2
3
4
5
6
7
8
OGCMN :old代中初始化(最小)的大小 (KB)
OGCMX :old代的最大容量(KB)
OGC :old代当前新生成的容量 (KB)
OC :Old代的容量 (KB)
YGC :从应用程序启动到采样时年轻代中gc次数
FGC :从应用程序启动到采样时old代(全gc)gc次数
FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
  1. 统计gc信息

    jstat -gcutil pid

    jstat -gcutil pid 1000 10 每1s打印一次gc信息,总共打印10次

1
2
3
4
5
6
7
8
9
10
11
12
S0 :年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1 :年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E :年轻代中Eden(伊甸园)已使用的占当前容量百分比
O :old代已使用的占当前容量百分比
P :perm代已使用的占当前容量百分比
M: Metaspace utilization as a percentage of the space's current capacity. 元空间
CCS: Compressed class space utilization as a percentage. 压缩类空间利用率为百分比。
YGC :从应用程序启动到采样时年轻代中gc次数
YGCT :从应用程序启动到采样时年轻代中gc所用时间(s)
FGC :从应用程序启动到采样时old代(全gc)gc次数
FGCT :从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT:从应用程序启动到采样时gc用的总时间(s)
  1. 显示垃圾回收的相关信息,同时显示最后一次或当前正在发生的垃圾回收的诱因。

    jstat -gccause pid

1
2
LGCC:最后一次GC原因
GCC:当前GC原因(No GC 为当前没有执行GC)
  1. 当前jvm执行的信息。

    jstat -printcompilation pid

1
2
3
4
Compiled :编译任务的数目
Size :方法生成的字节码的大小
Type:编译类型
Method:类名和方法名用来标识编译的方法。类名使用/做为一个命名空间分隔符。方法名是给定类中的方法。上述格式是由-XX:+PrintComplation选项进行设置的。

jhat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Usage:  jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [-debug <int>] [-version] [-h|-help] <file>

-J<flag> Pass <flag> directly to the runtime system. For
example, -J-mx512m to use a maximum heap size of 512MB
-stack false: Turn off tracking object allocation call stack.
-refs false: Turn off tracking of references to objects
-port <port>: Set the port for the HTTP server. Defaults to 7000
-exclude <file>: Specify a file that lists data members that should
be excluded from the reachableFrom query.
-baseline <file>: Specify a baseline object dump. Objects in
both heap dumps with the same ID and same class will
be marked as not being "new".
-debug <int>: Set debug level.
0: No debug output
1: Debug hprof file parsing
2: Debug hprof file parsing, no server
-version Report version number
-h|-help Print this help and exit
<file> The file to read

For a dump file that contains multiple heap dumps,
you may specify which dump in the file
by appending "#<number>" to the file name, i.e. "foo.hprof#3".

All boolean options default to "true"

官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jhat.html#CIHHJAGE

  1. jhat是用来分析jmap生成dump文件的命令,jhat内置了应用服务器,可以通过网页查看dump文件分析结果,jhat一般是用在离线分析上。

    jhat dump.hprof

image-20200510183006311

访问localhost:7000,所看到的页面如下图所示:image-20200510183036837

jconsole,jvisualvm

除了可以使用jhat来分析堆dump文件,也可以使用jconsole,或者jvisualvm来分析。

jconslole官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jconsole.html#CACCABEH

image-20200510180852531

image-20200510180955877

image-20200510181111192

jvisualvm官方文档

https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jvisualvm.html#CBBEGDEJ

分析堆dump文件

image-20200510174432414

image-20200510174531583

CPU占用率高:image-20200510174951554

其它命令

  1. 查看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
2
3
4
5
6
7
8
1) 死锁, Deadlock (重点关注)
2) 执行中,Runnable
3) 等待资源,Waiting on condition(重点关注)
4) 等待获取监视器,Waiting on monitor entry(重点关注)
暂停,Suspended
5) 对象等待中,Object.wait() 或 TIMED_WAITING
6) 阻塞,Blocked(重点关注,只有synchronized这种方式的锁(monitor锁)才会让线程出现BLOCKED状态,等待ReentrantLock则不会)
7) 停止,Parked(LockSupport两组方法park/parkNanos/parkUntil,使用带参数Object blocker的,jstack输出中会显示更详细的线程信息)

参考

  1. Oracle官方文档
显示评论