注意
想法及时记录,实现可以待做。
JVM问题排查
线上环境要排查JVM的问题,可以通过自带的命令行查看信息,方便定位问题所在。
jcmd
发送指定的命令请求给JVM,从而获取信息。
命令格式:
jcmd [-l|-h|-help]
jcmd pid|main-class PerfCounter.print
jcmd pid|main-class -f filename
jcmd pid|main-class command[ arguments]
通过-h
参数,查看帮助信息:
root:/# jcmd -h
Usage: jcmd <pid | main class> <command ...|PerfCounter.print|-f file>
or: jcmd -l
or: jcmd -h
command must be a valid jcmd command for the selected jvm.
Use the command "help" to see which commands are available.
If the pid is 0, commands will be sent to all Java processes.
The main class argument will be used to match (either partially
or fully) the class used to start Java.
If no options are given, lists Java processes (same as -p).
PerfCounter.print display the counters exposed by this process
-f read and execute commands from the file
-l list JVM processes on the local machine
-h this help
查看进程列表:
root:/# jcmd -l
1 app.jar
25039 sun.tools.jcmd.JCmd -l
查看更多的帮助信息:
root:/# jcmd 1 help
1:
The following commands are available:
VM.native_memory
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
VM.classloader_stats
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.finalizer_info
GC.heap_info
GC.run_finalization
GC.run
VM.uptime
VM.dynlibs
VM.flags
VM.system_properties
VM.command_line
VM.version
help
For more information about a specific command use 'help <command>'.
这里可以看到,通过jcmd
可以看到很多GC和JVM的信息,有助于排查问题。
jcmd用法示例
- dump堆转储文件
root:/# jcmd 1 help GC.heap_dump
1:
GC.heap_dump
Generate a HPROF format dump of the Java heap.
Impact: High: Depends on Java heap size and content. Request a full GC unless the '-all' option is specified.
Permission: java.lang.management.ManagementPermission(monitor)
Syntax : GC.heap_dump [options] <filename>
Arguments:
filename : Name of the dump file (STRING, no default value)
Options: (options must be specified using the <key> or <key>=<value> syntax)
-all : [optional] Dump all objects, including unreachable objects (BOOLEAN, false)
root:/# jcmd 1 GC.heap_dump filename.hprof
- 堆信息
root:/app# jcmd 1 GC.heap_info
1:
PSYoungGen total 152576K, used 51763K [0x00000000f6a00000, 0x0000000100000000, 0x0000000100000000)
eden space 151552K, 34% used [0x00000000f6a00000,0x00000000f9c8cde8,0x00000000ffe00000)
from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
to space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
ParOldGen total 153600K, used 50398K [0x00000000ed400000, 0x00000000f6a00000, 0x00000000f6a00000)
object space 153600K, 32% used [0x00000000ed400000,0x00000000f0537b68,0x00000000f6a00000)
Metaspace used 103304K, capacity 108732K, committed 109568K, reserved 1144832K
class space used 12478K, capacity 13341K, committed 13568K, reserved 1048576K
jps
jps(JVM Process Status Tool) (opens new window)是虚拟机进程状态工具。它可以显示指定系统内所有的 HotSpot 虚拟机进程状态信息。jps 通过 RMI 协议查询开启了 RMI 服务的远程虚拟机进程状态。
命令格式:
jps [options] [hostid]
jps [-help]
常用的参数:
- options: 选项参数
- m: 输出JVM的启动主类main的参数
- l: 输出主类的全名
- v: 显示船体给JVM的参数
- q: 仅输出本地JVM的进程ID
- V: 仅输出本地的JVM标识符
- hostid: 如果不指定,默认为当前主机
jps用法示例
$ jps
18027 Java2Demo.JAR
18032 jps
18005 jstat
$ jps -q
8841
1292
5398
$ jps -l remote.domain
3002 /opt/jdk1.7.0/demo/jfc/Java2D/Java2Demo.JAR
2857 sun.tools.jstatd.jstatd
jstat
jstat(JVM statistics Monitoring) (opens new window),是虚拟机统计信息监视工具。jstat 用于监视虚拟机运行时状态信息,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。
命令格式:
jstat [ generalOption | outputOptions vmid [ interval[s|ms] [ count ] ]
常用参数:
- option: 选项参数,用于指定用户需要查询的虚拟机信息
- class: 监视类装载、卸载数量、总空间以及类装载所耗费的时间
- compiler: 显示 JIT 编译的相关信息
- gc: 监视 Java 堆状况,包括 Eden 区、两个 survivor 区、老年代、永久代等区的容量、已用空间、GC 时间合计等信息。
- gccapacity: 显示各个代的容量以及使用情况
- gccause: 显示垃圾回收的相关信息(通 -gcutil),同时显示最后一次或当前正在发生的垃圾回收的诱因
- gcnew: 显示新生代信息
- gcnewcapacity: 显示有关新生代大小及其相应空间的统计信息
- gcold: 显示老年代和永久代的信息
- gcoldcapacity: 显示老年代的大小
- gcmetacapacity: 显示 Metaspace 的大小
- gcutil: 显示垃圾回收统计信息
- printcompilation: 显示Java HotSpot VM编译方法统计信息。
- vmid: 进程ID
jstat用法示例
jstat -class pid
输出参数:
- Loaded: 加载 class 的数量
- Bytes: 所占用空间大小
- Unloaded: 未加载数量
- Bytes: 未加载占用空间
- Time: 时间
$ jstat -class 7129
Loaded Bytes Unloaded Bytes Time
26749 50405.3 873 1216.8 19.75
jstat -compiler pid
输出参数:
- Compiled: 编译数量
- Failed: 失败数量
- Invalid: 不可用数量
- Time: 时间
- FailedType: 失败类型
- FailedMethod: 失败的方法
$ jstat -compiler 7129
Compiled Failed Invalid Time FailedType FailedMethod
42030 2 0 302.53 1 org/apache/felix/framework/BundleWiringImpl$BundleClassLoader findClass
jstat -gc pid time
输出参数:
- S0C:年轻代中 To Survivor 的容量(单位 KB);
- S1C:年轻代中 From Survivor 的容量(单位 KB);
- S0U:年轻代中 To Survivor 目前已使用空间(单位 KB);
- S1U:年轻代中 From 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)。
$ jstat -gcutil 21891 250 7
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 97.02 70.31 66.80 95.52 89.14 7 0.300 0 0.000 0.300
0.00 97.02 86.23 66.80 95.52 89.14 7 0.300 0 0.000 0.300
0.00 97.02 96.53 66.80 95.52 89.14 7 0.300 0 0.000 0.300
91.03 0.00 1.98 68.19 95.89 91.24 8 0.378 0 0.000 0.378
91.03 0.00 15.82 68.19 95.89 91.24 8 0.378 0 0.000 0.378
91.03 0.00 17.80 68.19 95.89 91.24 8 0.378 0 0.000 0.378
91.03 0.00 17.80 68.19 95.89 91.24 8 0.378 0 0.000 0.378
$ jstat -gc 25196 1s 4
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
20928.0 20928.0 0.0 0.0 167936.0 8880.5 838912.0 80291.2 106668.0 100032.1 12772.0 11602.2 760 14.332 580 656.218 670.550
20928.0 20928.0 0.0 0.0 167936.0 8880.5 838912.0 80291.2 106668.0 100032.1 12772.0 11602.2 760 14.332 580 656.218 670.550
20928.0 20928.0 0.0 0.0 167936.0 8880.5 838912.0 80291.2 106668.0 100032.1 12772.0 11602.2 760 14.332 580 656.218 670.550
20928.0 20928.0 0.0 0.0 167936.0 8880.5 838912.0 80291.2 106668.0 100032.1 12772.0 11602.2 760 14.332 580 656.218 670.550
jmap
jmap(JVM Memory Map) (opens new window)是 Java 内存映像工具。jmap 用于生成堆转储快照(一般称为 heapdump 或 dump 文件)。jmap 不仅能生成 dump 文件,还可以查询 finalize 执行队列、Java 堆和永久代的详细信息,如当前使用率、当前使用的是哪种收集器等。
如果不使用这个命令,还可以使用 -XX:+HeapDumpOnOutOfMemoryError 参数来让虚拟机出现 OOM 的时候,自动生成 dump 文件。
命令格式:
jmap [options] pid
常用参数:
- options: 选项参数
- dump:[live,] format=b, file=filename: 生成堆转储快照。-dump:live 只保存堆中的存活对象。
- finalizerinfo: 显示在 F-Queue 队列等待执行 finalizer 方法的对象
- heap: 显示 Java 堆详细信息
- histo[:live]: 显示堆中对象的统计信息,包括类、实例数量、合计容量。-histo:live 只统计堆中的存活对象。
- clstats: 打印Java堆的类加载器的统计信息。对于每个类加载器,将打印其名称,激活程度,地址,父类加载器以及已加载的类的数量和大小。
- F: 强制。当pid不响应时,将此选项与jmap -dump或jmap -histo选项一起使用。在此模式下不支持live子选项。
- pid: 进程ID
jmap示例
生成 heapdump 快照,堆转储文件,可以用MAT打开进行堆的内存泄漏的分析。
$ jmap -dump:live,format=b,file=dump.hprof 28920
Dumping heap to /home/xxx/dump.hprof ...
Heap dump file created
查看实例数最多的类
$ jmap -histo 29527 | head -n 6
num #instances #bytes class name
----------------------------------------------
1: 13673280 1438961864 [C
2: 1207166 411277184 [I
3: 7382322 347307096 [Ljava.lang.Object;
查看指定进程的堆信息
注意:使用 CMS GC 情况下,jmap -heap PID 的执行有可能会导致 java 进程挂起。
$ jmap -heap 12379
Attaching to process ID 12379, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 17.0-b16
using thread-local object allocation.
Parallel GC with 6 thread(s)
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 83886080 (80.0MB)
NewSize = 1310720 (1.25MB)
MaxNewSize = 17592186044415 MB
OldSize = 5439488 (5.1875MB)
NewRatio = 2
SurvivorRatio = 8
PermSize = 20971520 (20.0MB)
MaxPermSize = 88080384 (84.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 9306112 (8.875MB)
used = 5375360 (5.1263427734375MB)
free = 3930752 (3.7486572265625MB)
57.761608714788736% used
From Space:
capacity = 9306112 (8.875MB)
used = 3425240 (3.2665634155273438MB)
free = 5880872 (5.608436584472656MB)
36.80634834397007% used
To Space:
capacity = 9306112 (8.875MB)
used = 0 (0.0MB)
free = 9306112 (8.875MB)
0.0% used
PS Old Generation
capacity = 55967744 (53.375MB)
used = 48354640 (46.11457824707031MB)
free = 7613104 (7.2604217529296875MB)
86.39733629427693% used
PS Perm Generation
capacity = 62062592 (59.1875MB)
used = 60243112 (57.452308654785156MB)
free = 1819480 (1.7351913452148438MB)
97.06831451706046% used
jstack
jstack(Stack Trace for java) (opens new window)是 Java 堆栈跟踪工具。jstack 用来打印目标 Java 进程中各个线程的栈轨迹,以及这些线程所持有的锁,并可以生成 java 虚拟机当前时刻的线程快照(一般称为 threaddump 或 javacore 文件)。
线程快照是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。
命令格式:
jstack [options] pid
常用参数:
- options: 选项参数
- F: 当正常输出请求不被响应时,强制输出线程堆栈
- l: 除堆栈外,显示关于锁的附加信息
- m: 打印 java 和 jni 框架的所有栈信息
- pid: 进程ID
jtack示例
$ jstack -F 8321
Attaching to process ID 8321, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
Deadlock Detection:
Found one Java-level deadlock:
=============================
"Thread2":
waiting to lock Monitor@0x000af398 (Object@0xf819aa10, a java/lang/String),
which is held by "Thread1"
"Thread1":
waiting to lock Monitor@0x000af400 (Object@0xf819aa48, a java/lang/String),
which is held by "Thread2"
Found a total of 1 deadlock.
Thread t@2: (state = BLOCKED)
Thread t@11: (state = BLOCKED)
- Deadlock$DeadlockMakerThread.run() @bci=108, line=32 (Interpreted frame)
Thread t@10: (state = BLOCKED)
- Deadlock$DeadlockMakerThread.run() @bci=108, line=32 (Interpreted frame)
Thread t@6: (state = BLOCKED)
Thread t@5: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=-1107318896 (Interpreted frame)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=116 (Interpreted frame)
- java.lang.ref.ReferenceQueue.remove() @bci=2, line=132 (Interpreted frame)
- java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame)
Thread t@4: (state = BLOCKED)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait(long) @bci=0 (Interpreted frame)
- java.lang.Object.wait() @bci=2, line=485 (Interpreted frame)
- java.lang.ref.Reference$ReferenceHandler.run() @bci=46, line=116 (Interpreted frame)
线程的状态描述:
线程状态 | 描述 |
---|---|
NEW | 线程还未启动 |
RUNNABLE | 线程正在JVM中执行 |
BLOCKED | 线程被阻塞,等待监视器锁 |
WAITING | 线程无限期地等待另一个线程执行特定的操作 |
TIMED_WAITING | 线程正在等待另一个线程执行一个动作,等待时间为指定的时间 |
TERMINATED | 线程已经退出 |
jinfo
jinfo(JVM Configuration info) (opens new window),是 Java 配置信息工具。jinfo 用于实时查看和调整虚拟机运行参数。如传递给 Java 虚拟机的-X(即输出中的 jvm_args)、-XX参数(即输出中的 VM Flags),以及可在 Java 层面通过System.getProperty获取的-D参数(即输出中的 System Properties)。
命令格式:
jinfo [option] pid
常用参数:
- options: 选项参数
- flags: 打印传递给JVM的命令行标志。
- sysprops: 输出系统属性,等同于 System.getProperties()
- pid: 进程ID
jinfo示例
$ jinfo -sysprops 29527
Attaching to process ID 29527, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.222-b10
...