jvm常用监控和诊断工具有jps, jstat, jmap,jstck, jcmd。
jps命令
jps命令用于查看正在运行的Java进程, 进程Id在jstat,jmap,jcmd等命令下会经常用到
语法:jps [-q] [-mlvV] [<hostid>]
常用:jps
; jps -lv
; jps能够查看正在运行的java进程, -l是列出全路径,-v是列出启动参数
例子:
C:\Users\Lenovo>jps
22080 OomTest
29040 Main
25812
14888 Jps
29628 Launcher
C:\Users\Lenovo>jps -l
19280 sun.tools.jps.Jps
22080 com.xmc.demo.test.OomTest
29040 org/netbeans/Main
25812
29628 org.jetbrains.jps.cmdline.Launcher
C:\Users\Lenovo>jps -v
13808 OomTest2 -Xms10m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/dump.hprof -javaagent:D:\IntelliJ IDEA 2020.2.1\lib\idea_rt.jar=14014:D:\IntelliJ IDEA 2020.2.1\bin -Dfile.encoding=UTF-8
jstat命令
jstat是用于监视虚拟机各种运行状态信息的命令行工具,它可以显示本地或远程虚拟机的类装载,内存,垃圾收集等信息在没有GUI图形界面工具的linux系统上,它是首选工具,常常用于检测垃圾回收及内存泄漏问题。
语法:jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
语法说明:<option>
表示选型,vmid即java进程id,可以通过jps命令查找, interval 表示每隔多少毫秒输入, count表示一共输出多少次。
常用的option选项有类型:
类装载信息相关: -class
垃圾回收相关:
-gc 显示与GC相关的堆信息,包括Eden,Survior, 老年代,永久代,元空间等的大小,可用大小等信息。
-gcutil 显示内容与-gc类似,但输出内容主要关注已使用空间占总空间的比例。
-gccause 显示内容与 -gcutil类似,但是多了当前GC的原因
-gcnew 显示新生代的gc情况
-gcold 显示老年代的gc情况
例子:
C:\Users\Lenovo>jps
29040 Main
25812
28052 Jps
21640 Launcher
26140 OomTest2
C:\Users\Lenovo>jstat -gc 26140
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
512.0 512.0 496.0 0.0 2048.0 194.2 7168.0 1121.4 4864.0 4010.6 512.0 440.5 2 0.003 0 0.000 0.003
C:\Users\Lenovo>jstat -gcutil 26140
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
96.88 0.00 9.48 15.64 82.45 86.03 2 0.003 0 0.000 0.003
C:\Users\Lenovo>jstat -gccause 26140
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
96.88 0.00 9.48 15.64 82.45 86.03 2 0.003 0 0.000 0.003 Allocation Failure No GC
C:\Users\Lenovo>jstat -gcnew 26140
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
512.0 512.0 496.0 0.0 7 15 512.0 2048.0 194.2 2 0.003
C:\Users\Lenovo>jstat -gcold 26140
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
4864.0 4010.6 512.0 440.5 7168.0 1121.4 2 0 0.000 0.003
# 每个1秒输出一次,一共输入5次
C:\Users\Lenovo>jstat -gc 25740 1000 5
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
512.0 512.0 504.0 0.0 2048.0 186.1 7168.0 1067.4 4864.0 4011.2 512.0 440.5 2 0.002 0 0.000 0.002
512.0 512.0 504.0 0.0 2048.0 186.1 7168.0 1067.4 4864.0 4011.2 512.0 440.5 2 0.002 0 0.000 0.002
512.0 512.0 504.0 0.0 2048.0 186.1 7168.0 1067.4 4864.0 4011.2 512.0 440.5 2 0.002 0 0.000 0.002
512.0 512.0 504.0 0.0 2048.0 186.1 7168.0 1067.4 4864.0 4011.2 512.0 440.5 2 0.002 0 0.000 0.002
512.0 512.0 504.0 0.0 2048.0 186.1 7168.0 1067.4 4864.0 4011.2 512.0 440.5 2 0.002 0 0.000 0.002
S0C表示survior0的大小, S1C表示survior1的大小, S0U表示survior0的使用大小, EC表示Eden区的大小,EU表示Eden区已经使用的带下, OC表示老年代的大小,OU表示老年代已使用大小,MC表示方法区大小,MU表示方法区已使用大小YGC表示young GC次数,YGCT表示young GC耗时, FGCT表示Full GC次数, FGCT表示full GC耗时, GCT表示GC总耗时(即YGCT + FGCT)。
大小512这些都是Kb,我在这个类启动的时候设置了堆大小-Xms10m -Xmx10m 是10m,默认的新生代与老年代的比例是1:2,就是说新生代大概是3M,老年代大概是7M;新生代中的Eden区与S0,S1的比例是8:1:1,这里大概看到的就是2048:512:512,有点不符合(这里可能是jvm动态调整了比例,除非显式设置比Eden区与survior区的比例),但是总体上看还是满足Eden区比s0和s1大的特点。
通过每隔多少秒把堆信息和GC信息打出来,如果是短时间内多次Full GC,但是Full GC之后老年代的内存还不释放,意味着就内存泄漏的情况(程序执行了,对象没办法释放,导致内存被占用,比如一个全局的静态list一直在添加对象,这个list没办法被回收)。
jmap命令
jmap导出dump文件,dump文件用于查看java堆的使用情况,对象,类等信息。dump文件导出后可以用visual VM等工具查看。
语法:jmap [option] <pid>
option说明:
-heap 输出堆信息,包括GC,内存使用情况。
-dump 用于生成dump文件
-histo[:live] 输出堆中的对象统计信息,包括类,实例数量合计数量等。 :live表示只统计堆中存活的对象。
常用命令:
手动导出:jmap -dump:format=b,file=dumpName.hprof 进程id
format=b表示的是dump文件的格式是hprof类型,只需要把file后面的文件路径和文件名称修改一下就能使用了
程序发生OOM时自动导出:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/dump.hprof
例如在java程序配置如下参数,当堆超过100m导致程序崩溃的时候会输出dump文件:-Xmx100m -Xms100m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/dump.hprof
例子:
C:\Users\Lenovo>jmap -heap 25740
Attaching to process ID 25740, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11
using thread-local object allocation.
Parallel GC with 13 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 10485760 (10.0MB)
NewSize = 3145728 (3.0MB)
MaxNewSize = 3145728 (3.0MB)
OldSize = 7340032 (7.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 2097152 (2.0MB)
used = 1947192 (1.8569869995117188MB)
free = 149960 (0.14301300048828125MB)
92.84934997558594% used
From Space:
capacity = 524288 (0.5MB)
used = 32768 (0.03125MB)
free = 491520 (0.46875MB)
6.25% used
To Space:
capacity = 524288 (0.5MB)
used = 0 (0.0MB)
free = 524288 (0.5MB)
0.0% used
PS Old Generation
capacity = 7340032 (7.0MB)
used = 4323504 (4.1232147216796875MB)
free = 3016528 (2.8767852783203125MB)
58.903067452566965% used
5919 interned Strings occupying 497608 bytes.
jmap -histo:live 25740 执行后看一下有几千个类,我只列出部分。
C:\Users\Lenovo>jmap -histo:live 25740
num #instances #bytes class name
----------------------------------------------
1: 8571 802080 [C
2: 705 328512 [B
3: 1830 206632 java.lang.Class
4: 8410 201840 java.lang.String
5: 931 155520 [I
6: 1819 97664 [Ljava.lang.Object;
7: 464 40832 java.lang.reflect.Method
8: 1156 36992 java.util.HashMap$Node
9: 881 35240 java.util.TreeMap$Entry
10: 206 20768 [Ljava.util.HashMap$Node;
11: 489 19560 java.lang.ref.SoftReference
12: 512 18896 [Ljava.lang.String;
13: 319 15312 java.util.HashMap
14: 370 14800 java.util.LinkedHashMap$Entry
15: 443 14176 java.util.concurrent.ConcurrentHashMap$Node
16: 219 14016 java.net.URL
17: 319 12760 java.lang.ref.Finalizer
18: 201 11256 java.lang.invoke.MemberName
导出堆的dump文件,在生产或测试环境导出后先压缩(一般来说都有几百M),然后再拿到window本地解压使用visual VM等工具进行查看
C:\Users\Lenovo>jmap -dump:format=b,file=d:\aa.hprof 30136
Dumping heap to D:\aa.hprof ...
Heap dump file created
C:\Users\Lenovo>jmap -dump:live,format=b,file=D:\bb.hprof 30136
Dumping heap to D:\bb.hprof ...
Heap dump file created
测试代码:
public class OomTest2 {
public static void main(String[] args) throws InterruptedException {
List<byte[]> list = new ArrayList<>();
while (true) {
User user = new User();
user.setName("11234ac");
list.add(new byte[1024]);
Thread.sleep(20);
}
}
}
项目启动参数-Xms5m -Xmx5m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/dump.hprof
,当发生OOM后会自动把dump文件输出到D:/dump.hprof
jstack命令
jstack查看线程快照,可以通过jstacck获取的线程快照来分析线程长时间停顿的原因,如死锁,死循环,请求外部资源导致的长时间等待等。一般来说用得比较少,都是用分布式锁了。如果程序还是比较多的synchronized和Lock这类型jvm的锁,则可以通过jstack命令帮助我们解决问题。
重点关注:DeadLock, Waiting on condition,Waiting on monitor entry, Blocked 这几种情况,这些情况都是非正常情况。
语法:jstack 进程id
C:\Users\Lenovo>jstack 13808
2022-08-20 21:27:26
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode):
"Service Thread" #19 daemon prio=9 os_prio=0 tid=0x0000000017956800 nid=0x34a8 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread11" #18 daemon prio=9 os_prio=2 tid=0x00000000179cf800 nid=0x77f4 waiting on condition [0x0000000000000000]
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x000000001420e000 nid=0x71d8 in Object.wait() [0x000000001753e000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000fffa5d90> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x00000000fffa5d90> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"main" #1 prio=5 os_prio=0 tid=0x0000000003665000 nid=0x6c74 waiting on condition [0x00000000033ef000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(Native Method)
at com.xmc.demo.test.OomTest2.main(OomTest2.java:23)
"VM Thread" os_prio=2 tid=0x0000000015c84800 nid=0x3c9c runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x000000000367b800 nid=0x5ec8 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x000000000367d000 nid=0x6384 runnable
jcmd命令
jcmd 是jkd1.7之后官方提供的一个多功能的工具, 用来实现除了jstat之外的所有功能,如jps,jmap,jstack,官方推荐使用jcmd命令替代jmap命令。
语法:jcmd -l
列出所有的java进程,相当于jps
jcmd 进程id help
列出该进程支持的命令
例子:
C:\Users\Lenovo>jcmd 13808 help
13808:
The following commands are available:
JFR.stop
JFR.start
JFR.dump
JFR.check
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.run_finalization
GC.run
VM.uptime
VM.flags
VM.system_properties
VM.command_line
VM.version
help
#输出dump文件
C:\Users\Lenovo>jcmd 13808 GC.heap_dump D:/ccc.hprof
13808:
Heap dump file created