Java虚拟机性能分析和故障排查工具
JDK命令行工具
JDK提供了很多工具供java程序员使用
D:\Java\JDK1.8.0_211\bin
想要往高级发展,就必须得熟练使用几种常用的jdk工具。
1. jps
JVM Process Status Tool
显示指定系统内所有的虚拟机进程
1.1 作用
列出正在运行的虚拟机进程,并显示虚拟机执行主类(main所在的类)名称以及这些进程的本地虚拟机唯一ID:Local Virtual Machine Identifier,LVMID。
虽然功能比较单一,但他是使用频率最高的JDK命令行工具,因为其他的JDK工具大多需要输入唯一ID来确定要监控的是拿一个虚拟机进程。对于本地虚拟机进程来说,唯一ID与操作系统的进程ID是一致的。使用windows的任务管理器或者unix的ps命令也能查询到虚拟机进程的唯一ID,但如果同时启动多个虚拟机进程,无法根据进程名称定位时,那只有依赖jps命令显示主类的功能才能区分。
1.2 命令
jps[options][hostid]
options:
-q:显示进程ID
-m:显示进程ID、主类名称、传入main方法的参数
-l:显示进程ID、主类全名
-v:显示进程ID、主类名称、传入JVM的参数
-V:显示进程ID、主类名称
[-mlvV]:可以任意组合使用
hostid:
主机或者服务器的ip,如果不指定默认使用当前主机。
注意:如果需要查看其它机器上的jvm进程,需要在待查看的机器上启动jstatd。
2. jstat
JVM statistics Monitoring Tool
用于收集虚拟机各方面的运行数据
2.1 作用
监视虚拟机各种运行状态信息,可以显示本地或者是远程虚拟机进程中的类加载器、内存、垃圾收集、JIT编译等运行数据。
2.2 命令
jstat[option vmid[interval [count]]] <pid>
option:
表示用户希望查询的虚拟机信息,主要分三类:类加载器、垃圾收集和运行期编译状况
-class:显示有关类加载器行为的统计信息
-compiler:显示有关Java HotSpot VM即时编译器行为的统计信息
-gc:显示有关垃圾收集堆行为的统计信息
-gccapacity:显示有关各个垃圾回收代容量及其相应空间的统计信息
-gccaouse:显示有关垃圾收集统计信息(同-gcutil),以及上一次和当前(如果适用)垃圾收集事件的原因
-gcnew:显示新生代行为的统计信息
-gcnewcapacity:显示有关新生代大小及其相应空间的统计信息
-gcold:显示有关老年代行为的统计信息和元空间统计信息
-gcoldcapacity:显示有关老年代大小的统计信息
-gcmetacapacity:显示有关元空间大小的统计信息
-gcutil:显示有关垃圾收集统计信息
-printcompilation:显示Java HotSpot VM编译方法统计信息
vmid:
如果是本地虚拟机进程,vmid和本地虚拟机唯一ID是一致的。
如果是远程虚拟机进程,那vmid的格式应当是:
protocol:lvmid[@hostname[:port]/servername]
interval:
采样间隔,单位为秒s或者毫秒ms
默认单位毫秒,必须是正整数。
指定后,该jstat命令将在每个间隔产生并输出
count:
要显示的样本数
注意:参数interval和count代表查询间隔和次数,如果省略这两个参数,说明只查询一次如:
jstat -gc 8888
2.2 演示
2.2.1 -interval -count
...\study-jvmTools>jstat -gc 13676 500 8
解释:
查看13676ID的堆gc情况,每500ms执行一次,收集8条信息。
2.2.2 -class
...\study-jvmTools>jstat -class 13676
Loaded Bytes Unloaded Bytes Time
606 1225.1 0 0.0 0.20
解释:
类加载器统计信息
- Loaded:已加载的类数量
- Bytes:已加载的类所占空间大小 KB
- Unloaded:已施放的类数量(加载完不需要使用的类释放掉)
- Bytes:已释放的类所占空间大小 KB
- Time:加载到施放的总耗时
2.2.3 -compiler
...\study-jvmTools>jstat -compiler 13676
Compiled Failed Invalid Time FailedType FailedMethod
66 0 0 0.04 0
解释:
Java HotSpot VM即时编译器统计信息
- Compiled:执行的编译任务数
- Failed:执行的编译任务失败次数
- Invalid:无效的编译任务数
- Time:执行编译任务所花费的时间
- FailedType:编译失败的类型
- FailedMethod:编译失败的类名和方法名
2.2.4 -gc
...\study-jvmTools>jstat -gc 15072
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1024.0 1024.0 0.0 0.0 8192.0 5037.8 10240.0 0.0 4480.0 775.8 384.0 76.4 0 0.000 0 0.000 0.000
解释:(单位 KB)
-
S0C:幸存区一内存总大小
-
S1C:幸存区二内存总大小
-
S0U:幸存区一内存使用大小
-
S1U:幸存区二内存使用大小
-
EC:伊甸园区内存总大小
-
EU:伊甸园区内存使用大小
-
OC:老年代内存总大小
-
OU:老年代内存使用大小
-
MC:元空间内存总大小
-
MU:元空间内存使用大小
-
CCSC:压缩类空间总大小
-
CCSU:压缩类空间使用大小
-
YGC:youngGC的次数
-
YGCT:youngGC所耗费的时间
-
FGC:fullGC的次数
-
FGCT:fullGC所耗费的时间
-
GCT:gc总共耗费的时间
2.2.4 -gc
...\study-jvmTools>jstat -gcutil 15072
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 61.50 0.00 17.32 19.90 0 0.000 0 0.000 0.000
与-gc相似,但-gcutil展示的是使用/总内存的百分比
3. jinfo
Configuration info forjava
3.1 作用
实时地查看和调整虚拟机各项参数,但调整的仅仅是当次启动的程序,重启不生效。
3.2 命令
jinfo [option] <pid>
options:
- 若无则输出全部参数和系统属性
- -flag name:输出对应名称的参数
- -flag [+|-] name:开启或关闭对应名称的参数
- -flag name=value:设定对应名称的参数
- -flags:输出全部的参数
- -sysprops:输出系统属性
3.3 演示
3.3.1 jinfo
...\study-jvmTools>jinfo 14708
显示全部虚拟机参数和系统属性
3.3.2 -flag name
\study-jvmTools>jinfo -flag PrintGCDetails 14708
-XX:-PrintGCDetails
查看gc打印参数的状态
3.3.3 -flag [+|-]name
\study-jvmTools>jinfo -flag +PrintGCDetails 14708
\study-jvmTools>jinfo -flag PrintGCDetails 14708
-XX:+PrintGCDetails
将gc打印参数设置为开启
3.3.4 -flag name=value
\study-jvmTools>jinfo -flag HeapDumpPath=D:\ 14708
\study-jvmTools>jinfo -flag HeapDumpPath 14708
-XX:HeapDumpPath=D:\
将堆存储文件的路径改为 D盘根目录
4. jmap
Memory map for java
生成虚拟机的内存转储快照(heapdump文件)
4.1 作用
jmap是一个多功能命令,它可以生成java程序的dump文件,也可以查看对内对象信息、查看ClassLoader的信息以及finalizer队列
4.2 命令
jmap [options] <pid>
options:
- no:查看进程的内存映射信息,类似Solaris pmap命令
- -heap:显示java堆详细信息
- -histo[:live]:显示堆中对象的统计信息
- -clstats:打印类加载信息
- -finalizerinfo:显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象
- -dump: 生成堆转储快照
4.3 演示
4.3.1 jmap
打印目标虚拟机中加载的每个共享对象的起始地址、映射大小以及共享对象文件的路径全称。
...\study-jvmTools>jmap 10700
Attaching to process ID 10700, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12
0x0000000055590000 8852K D:\Java\jdk1.8.0_211\jre\bin\server\jvm.dll
0x0000000055e40000 840K D:\Java\jdk1.8.0_211\jre\bin\msvcr100.dll
0x00007ff7c79f0000 220K D:\Java\jdk1.8.0_211\bin\java.exe
4.3.2 -heap
显示Java堆详细信息
打印一个堆的摘要信息,包括使用的GC算法、堆配置信息和各内存区域内存使用信息。
...\study-jvmTools>jmap -heap 10700
Attaching to process ID 10700, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12
using thread-local object allocation.
Parallel GC with 8 thread(s)
Heap Configuration: # jvm的内存配置信息
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 1864368128 (1778.0MB)
NewSize = 38797312 (37.0MB)
MaxNewSize = 621281280 (592.5MB)
OldSize = 78643200 (75.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 = 29360128 (28.0MB)
used = 4114936 (3.9243087768554688MB)
free = 25245192 (24.07569122314453MB)
14.015388488769531% used
From Space: #幸存区1
capacity = 4718592 (4.5MB)
used = 0 (0.0MB)
free = 4718592 (4.5MB)
0.0% used
To Space: #幸存区2
capacity = 4718592 (4.5MB)
used = 0 (0.0MB)
free = 4718592 (4.5MB)
0.0% used
PS Old Generation # 老年代
capacity = 78643200 (75.0MB)
used = 0 (0.0MB)
free = 78643200 (75.0MB)
0.0% used
3153 interned Strings occupying 258944 bytes.
4.3.3 -histo:live
显示堆中对象的统计信息
其中包括每个java类、对象数量、内存大小(B)、类完全限定名、打印的虚拟机内部的类名称将会带有一个“*”前缀,如果指定了live子项,则只计算活动的对象。
\study-jvmTools>jmap -histo:live 10700
# num 序号 #instances对象个数 #bytes对象占内存 class name
----------------------------------------------
1: 4565 428432 [C
2: 422 141584 [B
3: 4417 106008 java.lang.String
4: 687 78536 java.lang.Class
5: 625 41000 [Ljava.lang.Object;
4.3.4 -clstats
打印类加载器信息
-clstats是-permstat的替代方法,在JDK8之前 -permstat用来打印类加载器的数据
打印java堆内存的永久保存区域的类加载器的只能统计信息,对于每个类加载器而言,它的名称、活跃度、地址、父类加载器、它所加载的类的数量和大小都会被打印
...\study-jvmTools>jmap -clstats 10700
Attaching to process ID 10700, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.............................................................................done.
class_loader classes bytes parent_loader alive? type
<bootstrap> 602 1128832 null live <internal>
0x0000000090e1a3c0 4 5144 0x0000000090e1a430 live sun/misc/Launcher$AppClassLoader@0x000000010000f8d8
0x0000000090e1a430 0 0 null live sun/misc/Launcher$ExtClassLoader@0x000000010000fc80
0x0000000090ea2e78 0 0 0x0000000090e1a3c0 live java/util/ResourceBundle$RBClassLoader@0x0000000100063f98
total = 4 606 1133976 N/A alive=4, dead=0 N/A
class_loader:类加载器
classes:数量
parent_loader:父加载器
alive:存活状态
type:类型
4.3.5 -finalizerinfo
打印等待执行finalizer方法的对象信息
\study-jvmTools>jmap -finalizerinfo 10700
Attaching to process ID 10700, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.211-b12
Number of objects pending for finalization: 0
4.3.6 -dump
生成堆存储快照dump文件
以二进制格式转储java堆到指定filename的文件中。
live子选项是可选,如果指定则堆中只有活动的对象会被转储。
想要查看heap dump文件,需要使用jhat工具
\study-jvmTools>jmap -dump:live,format=b,file=D:\jmap.bin 10700
Dumping heap to D:\jmap.bin ...
Heap dump file created
5. jhat
JVM Heap Dump Browser
5.1 作用
与jmap搭配使用,分析jmap生成的堆转储快照。jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,可以在浏览器中查看。
这个工具一般在没有其它工具可以使用的情况下使用。主要原因:1、一般不会在部署应用程序的服务器上直接分析dump文件,即使可以这样做,也会尽量将dump文件拷贝到其它机器上进行分析,因为分析工作是一个耗时且耗资源的过程,既然都要在其它机器上进行分析就没必要收到命令行工具的限制了;2、jhat的分析功能相对来说比较简陋,其它有较好的替代工具,比如VisualVM,以及专业用语分析dump文件的Eclipse Memory Anlyzer、IBM HeapAnlyzer等工具都能实现比jhat更强大更专业的分析功能。
5.2 命令
jhat [options] 堆转储文件
options:
- -stack:开关对象分配调用栈跟踪(tracking object allocation call stack),如果分配位置信息在堆转储中不可用,则必须将此标志设置为false,默认值为true
- -refs:开关对象引用跟踪(tracking of references to objects)。默认值为true,默认情况下返回的指针是指向其他特定对象的对象,如反向链接或输入引用(referrers or incoming references)会统计/计算堆中的所有对象
- -port:设置jhat HTTP server的端口号,默认值7000
- -exclude:指定对象查询时需要排除的数据成员列表文件(列出应从访问对象查询中排除的数据成员的文件)。例如:如果文件列列出了java.lang.String.value,那么当从某个特定对象Object计算可达的对象列表时,引用路径涉及java.lang.String.value的都会被排除
- -baseline:指定一个基准堆转储(baseline heap dump)。在两个heap dumps中有相同object ID的对象会被标记为不是新的(marked as not being new)。其它对象被标记为新的(new)。在比较两个不同的堆转储时很有用。
- -debug:设置debug级别,0表示不输出调试信息。值越大则表示输出更详细的debug信息。
- -version:启动后只显示版本信息就退出
堆转储文件:
要浏览的java二进制堆转储文件路径
5.3 演示
\study-jvmTools>jhat D:\jmap.bin
Reading from D:\jmap.bin...
Dump file created Sat Oct 10 15:30:39 CST 2020
Snapshot read, resolving...
Resolving 15030 objects...
WARNING: Failed to resolve object id 0x90e4f548 for field type (signature L)
WARNING: Failed to resolve object id 0x90e6f948 for field type (signature L)
WARNING: Failed to resolve object id 0x90e4f4d8 for field type (signature L)
WARNING: Failed to resolve object id 0x90e4f468 for field type (signature L)
WARNING: Failed to resolve object id 0x90e6f9e8 for field type (signature L)
WARNING: Failed to resolve object id 0x90e4f7d0 for field type (signature L)
WARNING: Failed to resolve object id 0x90e69530 for field type (signature L)
Chasing references, expect 3 dots...
Eliminating duplicate references...
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
6. jstack
Stack Trace forjava
6.1 作用
查看或导出java应用程序中堆栈信息。
线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、长时间等待外部资源等。线程出现停顿的时候通过jstack来查看各个线程调用堆栈,就可以知道没有相应的线程到底在后台做什么事情,活着等待什么资源。如果java程序崩溃生成core文件,jstack工具可以用来获取core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题。另外,jstack工具还可以附属到正在运行的java程序中,看到当前运行的java程序的java stack和native stack信息。
6.2 命令
jstack [options] <pid>
options:
- -F:当前线程挂起时,使用jstack -l pid请求不被响应式,强制输出线程堆栈
- -l:除堆栈外,显示关于锁的附加信息,如:ownable synchronizers
- -m:可以同时输出java以及C/C++的堆栈信息
6.3 演示
6.3.1 死循环
运行程序,使用process explorer查看消耗cpu最多的线程id
这里查看的11040是十进制,转换为16进制后:2b20
...\study-jvmTools>jstack -l 13768
找到2b20对应的堆栈信息
找到java代码中的循环,分析、处理。
6.3.2 等待输入
直接定位到main线程
可看到线程状态为可运行,但是停在了等待输入的方法
6.3.3 死锁
执行jstack
JDK可视化工具
7. JConsole
查看Java应用程序的运行概况,监视垃圾收集器管理的虚拟机内存(堆和元空间)的变化趋势,以及监控程序内的线程。
7.1 内存
相当于命令行的jstat命令,用于监视收垃圾收集器管理的虚拟机内存(堆和元空间)的变化趋势,这不仅是包括堆内存的整体信息,更细化到伊甸园区、幸存区、老年代的使用情况。同事,也包括非堆区,即元空间的使用情况,单击界面右上角的“执行GC”按钮,可以强制应用程序金信一次full gc。
7.2 线程
相当于命令行的jstack命令,遇到线程停顿的时候可以使用它来尽兴监控分析。jConsole显示了系统内的线程数量,并在屏幕下方,显示了程序中所有的线程。单击线程名称,便可以查看线程的栈信息。
7.3 类
显示了系统以及装载的类数量,在详细信息栏中,还显示了已卸载的类数量。
7.4 VM摘要
在vm摘要页面,jconsole显示了当前应用程序的运行环境。包括虚拟机类型、版本、堆信息以及虚拟机参数等。相当于jinfo命令
7.5 MBean:
MBean页面允许通过jconsole访问已经在MBean服务器注册的MBean对象。
8. Visual VM
visual VM是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序,并且可以预见在未来一段时间内都是官方主力发展的虚拟机故障处理工具。官方在visualvm的软件说明书上写着“All-in-one”的描述,预示着他除了运行监视、故障处理外,还提供了很多其他方面的功能。如性能分析,visualvm的性能分析功能甚至比起很多专业收费的工具都不会逊色多少,而且visualvm还有一个很强大的优点:不需要被监视的程序基于特殊的运行,因此他对应用程序的时机性能影响很小,使得他可以直接应用在生产环境中。
VIsualVM基于NetBeans平台开发,因此他一开始就具备了插件扩展功能的特性,通过插件扩展支持,VisualVM可以做到:
- 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)
- 监视应用程序的cpu、gc、堆、方法区以及线程的信息(jstat、jstack)
- dump以及分析堆转储快照(jmap、jhat)
- 方法级的程序运行性能分析,找到被调用最多、运行时间最长的方法
- 离线程序快照:收集程序的运行是配置、线程dump、内存dump等信息建立一个快照,可以将快照发送开发者处进行bug反馈
- 其它plugs的不限可能性…
8.1 概述
8.2 监视
8.3 线程
8.4 抽样器
8.5 Profiler
8.6 插件
查看GC的插件:VIsualGC
很直观的查看到堆内存的变化
内存分析和线程分析
监视:
监视是一种用来查看应用程序运行时行为的一般方法。通常会有多个视图( View )分别实时地显示CPU使用情况、内存使用情况线程状态以及其他一些有用的信息,以便用户能很快地发现问题的关键所在。
转储:
性能分析工具从内存中获得当前状态数据并存储到文件用于静态的性能分析。Java程序是通过在启动Java程序时添加适当的条件
参数来触发转储操作的。它包括以下三种:
- 系统转储: JMM生成的本地系统的转储.又称作核心转储。一般的 ,系统转储数据量大.需要平台相关的工具去分析。如
Windows.上的windbg和Linux上的gdb. - Java转储: MM内部生成的格式化后的数据,包括线程信息.类的加载信息以及堆的统计数据。通常也用于检测死锁。
- 堆转储: MM将所有对象的堆内容存储到文件。
快照:
应用程序启动后,性能分析工具开始收集各种运行时数据,其中- 些数据直接 显示在监视视图中.而另外大部分数据被保存在内
部,直到用户要求获取快照,基于这些保存的数据的统计信息才被显示出来。快照包含了应用程序在- -段时间内的执行信息,通常有
CPU快照和内存快照两种类型:
- CPU快照:主要包含了应用程序中函数的调用关系及运行时间,这些信息通常可以在CPU快照视图中进行查看。
- 内存快照:主要包含了内存的分配和使用情况、载入的所有类.存在的对象信息及对象间的引用关系等。这些信息通常可以 在内存快照视图中进行查看。
性能分析:
性能分析是通过收集程序运行时的执行数据来帮助开发人员定位程序需要被优化的部分,从而提高5程序的运行速度或是内存使用效率,主要有以下三个方面:
-
CPU性能分析: CPU性能分析的主要目的是统计函数的调用情况及执行时间,或者更简单的情况就是统计应用程序的CPU使用情况。通常有CPU监视和CPU快照两种方式来显示CPU性能分析结果。
-
内存性能分析:内存性能分析的主要目的是通过统计内存使用情况检测可能存在的内存泄露问题及确定优化内存使用的方向。通常有内存监视和内存快照两种方式来显示内存性能分析结果。
-
线程性能分析:线程性能分析主要用于在多线程应用程序中确定内存的问题所在。一般包括线程的状态变化情况,死锁情况和某个线程在线程生命期内状态的分布情况等。