常用工具命令
概览
命令 | 描述 |
---|---|
jps | 与linux的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号 |
jstack | 查看jvm 线程运行状态,是否有死锁现象等等信息 |
jinfo | 可以输出并修改运行时的java 进程的opts |
jstat | 一个极强的监视VM 内存工具。可以用来监视VM 内存内的各种堆和非堆的大小及其内存使用量 |
jmap | 打印出某个java 进程(使用pid)内存内的所有’对象’的情况(如:产生那些对象,及其数量) |
jhat | 对dump文件进行分析 |
mat | 一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具 |
JSTAT
jstat工具特别强大,有众多的可选项,详细查看堆内各个部分的使用量,以及加载类的数量。
jstat -help
命令
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.
jstat -options
命令
-class:显示有关类加载器行为的统计信息
-compiler:显示有关Java HotSpot VM实时编译器行为的统计信息
-gc:显示有关垃圾回收堆行为的统计信息
-gccapacity:示有关代的容量及其相应空间的统计信息
-gccause:显示有关GC统计信息(gcutil与之相同)的摘要,以及最后一个和当前GC事件
的原因
-gcmetacapacity:显示有关新生代及其相应空间大小的统计信息
-gcnew:显示新生代行为的统计信息
-gcnewcapacity:显示有关老年代大小的统计信息
-gcold:显示有关老年代和Metaspace统计信息行为的统计信息
-gcoldcapacity:显示有关Metaspace大小的统计信息
-gcutil:显示有关垃圾回收统计信息的摘要
-printcompilation:显示Java HotSpot VM编译方法统计信息
jstat -class pid
:查看class加载统计,显示加载class的数量,及所占空间等信息
Loaded Bytes Unloaded Bytes Time
7886 14013.2 1 0.9 3.09
Loaded:加载class的数量
Bytes:所占用空间大小
Unloaded:未加载数量
Bytes:未加载占用空间
Time:执行类加载和卸载操作所花费的时间。
jstat -compiler pid
: 查看编译统计,显示VM 实时编译的数量等信息
Compiled Failed Invalid Time FailedType FailedMethod
3926 0 0 0.65 0
Compiled:执行的编译任务数
Failed:编译任务失败的次数
Invalid:已失效的编译任务数
Time:执行编译任务所花费的时间
FailedType:编译上次失败的编译的类型
FailedMethod:上次失败编译的类名和方法
jstat -gc pid
: 垃圾回收统计,可以显示gc信息,查看gc的次数,时间
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
11264.0 12800.0 0.0 0.0 158720.0 92701.5 113152.0 17765.7 35456.0 33718.6 4992.0 4596.9 8 0.031 2 0.040 0.071
指定打印的间隔和次数,每1秒中打印一次,共打印5次
jstat ‐gc pid 1000 5
S0C:第一个Survivor区的大小(KB)
S1C:第二个Survivor区的大小(KB)
S0U:第一个Survivor区的使用大小(KB)
S1U:第二个Survivor区的使用大小(KB)
EC:Eden区的大小(KB)
EU:Eden区的使用大小(KB)
OC:Old区大小(KB)
OU:Old使用大小(KB)
MC:方法区大小(KB)
MU:方法区使用大小(KB)
CCSC:压缩类空间大小(KB)
CCSU:压缩类空间使用大小(KB)
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
jstat -gccapacity pid
: 堆内存统计,三代(young,old,perm)内存使用和占用大小
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
76288.0 1213440.0 189952.0 11264.0 12800.0 158720.0 153088.0 2427904.0 113152.0 113152.0 0.0 1079296.0 35456.0 0.0 1048576.0 4992.0 8 2
jstat -gcnew pid
: 新生代垃圾回收统计
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
11264.0 12800.0 0.0 0.0 3 15 12800.0 158720.0 99500.0 8 0.031
jstat -gcnewcapacity pid
: 新生代内存统计
NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC
76288.0 1213440.0 189952.0 404480.0 11264.0 404480.0 12800.0 1212416.0 158720.0 8 2
jstat -gcold pid
: 老年代垃圾回收统计
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
35456.0 33718.6 4992.0 4596.9 113152.0 17765.7 8 2 0.040 0.071
jstat -gcutil PID 1000 100
: 1000ms 统计一次gc情况,总共统计100次
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 65.59 15.70 95.10 92.08 8 0.031 2 0.040 0.071
0.00 0.00 65.59 15.70 95.10 92.08 8 0.031 2 0.040 0.071
0.00 0.00 65.59 15.70 95.10 92.08 8 0.031 2 0.040 0.071
0.00 0.00 65.59 15.70 95.10 92.08 8 0.031 2 0.040 0.071
0.00 0.00 65.59 15.70 95.10 92.08 8 0.031 2 0.040 0.071
0.00 0.00 65.59 15.70 95.10 92.08 8 0.031 2 0.040 0.071
jstat -printcompilation PID 250 6
: 每250毫秒打印一次,一共打印6 次
Compiled Size Type Method
4390 18 1 java/net/InetSocketAddress$InetSocketAddressHolder access$800
4390 18 1 java/net/InetSocketAddress$InetSocketAddressHolder access$800
4390 18 1 java/net/InetSocketAddress$InetSocketAddressHolder access$800
4390 18 1 java/net/InetSocketAddress$InetSocketAddressHolder access$800
4390 18 1 java/net/InetSocketAddress$InetSocketAddressHolder access$800
4390 18 1 java/net/InetSocketAddress$InetSocketAddressHolder access$800
JINFO
jinfo是JDK自带命令,可以用来查看正在运行的java应用程序的扩展参数,包括Java System属性和JVM命令行参数。也可以动态的修改正在运行的JVM 一些参数。当系统崩溃时,jinfo可以从core文件里面知道崩溃的Java应用程序的配置信息
jinfo -help
命令
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
jinfo pid
:输出当前jvm进程的全部参数和系统属性
com.sun.management.jmxremote =
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = cn.ybzy.demo.DemoApplication
java.home = D:\Development\Java\jdk1.8\jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_271
java.ext.dirs = D:\Development\Java\jdk1.8\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
sun.boot.class.path = D:\Development\Java\jdk1.8\jre\lib\resources.jar;D:\Development\Java\jdk1.8\jre\lib\rt.jar;D:\Development\Java\jdk1.8\jre\lib\sunrsasign.jar;D:\Development\Java\jdk1.8\jre\lib\jsse.jar;D:\Development\Java\jdk1.8\jre\lib\jce.jar;D:\Development\Java\jdk1.8\jre\lib\charsets.jar;D:\Development\Java\jdk1.8\jre\lib\jfr.jar;D:\Development\Java\jdk1.8\jre\classes
java.awt.headless = true
java.vendor = Oracle Corporation
spring.application.admin.enabled = true
file.separator = \
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64
VM Flags:
Non-default VM flags: -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote -XX:CICompilerCount=4 -XX:InitialHeapSize=234881024 -XX:+ManagementServer -XX:MaxHeapSize=3728736256 -XX:MaxNewSize=1242562560 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=78118912 -XX:OldSize=156762112 -XX:TieredStopAtLevel=1 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line: -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:D:\Development\JetBrains\IntelliJ IDEA 2022.1.2\lib\idea_rt.jar=4556:D:\Development\JetBrains\IntelliJ IDEA 2022.1.2\bin -Dfile.encoding=UTF-8
jinfo -flag name pid
:可以查看指定的jvm 参数的值;打印结果:-无此参数,+有
jinfo -flag -UseParallelGC 11304
-XX:+UseParallelGC
jinfo -flag [+|-]name pid
:开启或者关闭对应名称的参数(无需重启虚拟机)
jinfo -flag -UseParallelGC 11304
jinfo -flag +UseParallelGC 11304
jinfo -flag name=value pid
:修改指定参数的值
jinfo -flags pid
:输出全部的参数
Attaching to process ID 11304, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.271-b09
Non-default VM flags: -XX:-BytecodeVerificationLocal -XX:-BytecodeVerificationRemote -XX:CICompilerCount=4 -XX:InitialHeapSize=234881024 -XX:+ManagementServer -XX:MaxHeapSize=3728736256 -XX:MaxNewSize=1242562560 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=78118912 -XX:OldSize=156762112 -XX:TieredStopAtLevel=1 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line: -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:D:\Development\JetBrains\IntelliJ IDEA 2022.1.2\lib\idea_rt.jar=4556:D:\Development\JetBrains\IntelliJ IDEA 2022.1.2\bin -Dfile.encoding=UTF-8
jinfo -sysprops pid
:输出当前jvm进行的全部的系统属性
com.sun.management.jmxremote =
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = cn.ybzy.demo.DemoApplication
java.home = D:\Development\Java\jdk1.8\jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.windows.WToolkit
java.vm.info = mixed mode
java.version = 1.8.0_271
java.ext.dirs = D:\Development\Java\jdk1.8\jre\lib\ext;C:\Windows\Sun\Java\lib\ext
sun.boot.class.path = D:\Development\Java\jdk1.8\jre\lib\resources.jar;D:\Development\Java\jdk1.8\jre\lib\rt.jar;D:\Development\Java\jdk1.8\jre\lib\sunrsasign.jar;D:\Development\Java\jdk1.8\jre\lib\jsse.jar;D:\Development\Java\jdk1.8\jre\lib\jce.jar;D:\Development\Java\jdk1.8\jre\lib\charsets.jar;D:\Development\Java\jdk1.8\jre\lib\jfr.jar;D:\Development\Java\jdk1.8\jre\classes
java.awt.headless = true
java.vendor = Oracle Corporation
spring.application.admin.enabled = true
file.separator = \
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = windows
sun.cpu.isalist = amd64
JMAP
jstat可以对jvm堆的内存进行统计分析,而jjmap可以获取到更加详细的内容,如:内存使用情况的汇总、对内存溢出的定位与分析
jmap可以生成heap dump文件,也可以查看堆内对象分析内存信息等,如果不使用这个命令,还可以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候自动生成dump文件。
jmap -help
命令
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
jmap -dump:live,format=b,file=dump.hprof pid
: 将jvm当前内存中的情况dump到文件中,然后对它进行分析。format指定输出格式,live指明是活着的对象,file指定文件名。
Dumping heap to C:\Users\Admin\dump.hprof ...
Heap dump file created
jmap -heap pid
: 查看内存使用情况,打印heap的概要信息,GC使用的算法,heap的配置和使用情况,可以用此来判断内存目前的使用情况以及垃圾回收情况
Attaching to process ID 11304, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.271-b09
using thread-local object allocation.
Parallel GC with 10 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 3728736256 (3556.0MB)
NewSize = 78118912 (74.5MB)
MaxNewSize = 1242562560 (1185.0MB)
OldSize = 156762112 (149.5MB)
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 = 157810688 (150.5MB)
used = 21083640 (20.10692596435547MB)
free = 136727048 (130.39307403564453MB)
13.360083697246159% used
From Space:
capacity = 5242880 (5.0MB)
used = 0 (0.0MB)
free = 5242880 (5.0MB)
0.0% used
To Space:
capacity = 13107200 (12.5MB)
used = 0 (0.0MB)
free = 13107200 (12.5MB)
0.0% used
PS Old Generation
capacity = 114294784 (109.0MB)
used = 18184528 (17.342117309570312MB)
free = 96110256 (91.65788269042969MB)
15.910199366578269% used
16895 interned Strings occupying 1655896 bytes.
jmap -finalizerinfo pid
: 打印等待回收的对象信息
Attaching to process ID 11304, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.271-b09
Number of objects pending for finalization: 0
jmap -histo:live pid
: 打印堆的对象统计,包括对象数、内存大小等。这个命令执行,JVM会先触发gc,然后再统计信息
# 查看所有对象,包括活跃以及非活跃的
jmap ‐histo <pid> | more
# 查看活跃对象
jmap ‐histo:live <pid> | more
num #instances #bytes class name
----------------------------------------------
1: 41238 4229144 [C
2: 41015 984360 java.lang.String
3: 11133 979704 java.lang.reflect.Method
4: 8415 931672 java.lang.Class
5: 9280 599072 [Ljava.lang.Object;
6: 17904 572928 java.util.concurrent.ConcurrentHashMap$Node
7: 11700 468000 java.util.LinkedHashMap$Entry
8: 4428 436768 [I
9: 5437 403432 [Ljava.util.HashMap$Node;
10: 1929 365776 [B
11: 5924 331744 java.util.LinkedHashMap
12: 13707 304496 [Ljava.lang.Class;
13: 3815 274680 java.lang.reflect.Field
3379: 1 16 sun.rmi.transport.DGCImpl_Skel
3380: 1 16 sun.rmi.transport.DGCImpl_Stub
3381: 1 16 sun.rmi.transport.proxy.RMIDirectSocketFactory
3382: 1 16 sun.rmi.transport.tcp.TCPTransport$1
3383: 1 16 sun.security.provider.NativeSeedGenerator
3384: 1 16 sun.util.calendar.Gregorian
3385: 1 16 sun.util.locale.provider.AuxLocaleProviderAdapter$NullProvider
3386: 1 16 sun.util.locale.provider.CalendarDataUtility$CalendarWeekParameterGetter
3387: 1 16 sun.util.locale.provider.SPILocaleProviderAdapter
3388: 1 16 sun.util.locale.provider.TimeZoneNameUtility$TimeZoneNameGetter
3389: 1 16 sun.util.resources.LocaleData
3390: 1 16 sun.util.resources.LocaleData$LocaleDataResourceBundleControl
Total 303249 15256016
对象说明
B byte
C char
D double
F float
I int
J long
Z boolean
[ 数组,如[I表示int[]
[L+类名 其他对象
jmap -clstats pid
: 打印Java类加载器的智能统计信息,对于每个类加载器而言,对于每个类加载器而言,它的名称,活跃度,地址,父类加载器,它所加载的类的数量和大小都会被打印。此外,包含的字符串数量和大小也会被打印
Attaching to process ID 11304, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.271-b09
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.liveness analysis may be inaccurate ...
class_loader classes bytes parent_loader alive? type
<bootstrap> 2414 4203574 null live <internal>
0x00000006e1c34ac0 1 1472 null dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e1c37ac0 1 1471 null dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e1c3a7c0 1 1472 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e2541950 1 880 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e1c381c8 1 1471 null dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e24b1840 1 1474 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e24b4590 1 881 null dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e24aeca0 1 1472 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e24af7a0 1 1472 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e2966078 1 1474 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e1c34930 1 880 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e1c37930 1 1471 null dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e25414a0 1 1471 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e1c38038 1 1471 null dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
0x00000006e2964768 1 1471 0x00000006e1c0de70 dead sun/reflect/DelegatingClassLoader@0x00000007c000a0a0
total = 120 7243 11663417 N/A alive=1, dead=119 N/A
jmap -F -histo pid
: -F 强制模式。 如果指定的pid 没有响应,请使用jmap -dump或jmap -histo选项。此模式不支持live子选项。
Attaching to process ID 11304, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.271-b09
Iterating over heap. This may take a while...
Object Histogram:
num #instances #bytes Class description
--------------------------------------------------------------------------
1: 56745 6587240 char[]
2: 47710 1145040 java.lang.String
3: 11275 992200 java.lang.reflect.Method
4: 8415 931672 java.lang.Class
5: 4671 845760 byte[]
6: 10688 684536 java.lang.Object[]
7: 17904 572928 java.util.concurrent.ConcurrentHashMap$Node
8: 5644 509016 int[]
9: 11882 475280 java.util.LinkedHashMap$Entry
10: 5766 436488 java.util.HashMap$Node[]
11: 6052 338912 java.util.LinkedHashMap
JHAT
将jvm的内存dump到文件中后,由于dump文件是一个二进制的文件,不方便查看,可以使用jhat工具进行查看
用法:jhat ‐port <port> <file>
[root@administrator ~]# jhat -port 8083 /root/dump.hprof
Reading from /root/dump.hprof...
Dump file created Thu Oct 13 22:11:40 CST 2022
Snapshot read, resolving...
Resolving 250364 objects...
Chasing references, expect 50 dots..................................................
Eliminating duplicate references..................................................
Snapshot resolved.
Started HTTP server on port 8083
Server is ready.
浏览器访问:IP:PORT
Object Query Language (OQL)查询功能
显示所有文件对象的文件路径
select file.path.value.toString() from java.io.File file
具体使用查看相关文档,以下是一些OQL Examples
select all Strings of length 100 or more
select s from java.lang.String s where s.value.length >= 100
select all int arrays of length 256 or more
select a from [I a where a.length >= 256
show content of Strings that match a regular expression
select s.value.toString() from java.lang.String s
where /java/.test(s.value.toString())
show path value of all File objects
select file.path.value.toString() from java.io.File file
show names of all ClassLoader classes
select classof(cl).name
from instanceof java.lang.ClassLoader cl
show instances of the Class identified by given id string
select o from instanceof 0xd404b198 o
MAT
MAT(Memory Analyzer Tool),一个基于Eclipse的内存分析工具,是一个快速、功能丰富的JAVA heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。使用内存分析工具从众多的对象中进行分析,快速的计算出在内存中对象的占用大小,看看是谁阻止了垃圾收集器的回收工作,并可以通过报表直观的查看到可能造成这种结果的对象
访问官网:https://www.eclipse.org/mat/
,下载MAT工具,并进行解压,双击MemoryAnalyzer.exe
启动
在菜单栏,选择File -> Open File处选择dump.hprof
文件打开,进入如下页面,默认选择,点击Finish
分析结果如下
需注意Histogram、Dominator Tree
参数
Histogram:列出内存中的对象,对象的个数以及大小
Dominator Tree:列出最大的对象以及其依赖存活的对象
JSTACK
jstack是jdk自带的线程堆栈分析工具,使用该命令可以查看或导出Java应用程序中线程堆栈信息。
主要作用是将正在运行的jvm的线程情况进行快照,并且打印出来
示例 | 描述 |
---|---|
jstack pid | 输出当前jvm进程的全部参数和系统属性 |
[root@administrator ~]# jstack 18876
2022-10-13 22:51:42
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.311-b11 mixed mode):
"arthas-command-execute" #54 daemon prio=5 os_prio=0 tid=0x00007f4f480a6800 nid=0xca61 waiting on condition [0x00007f4f70843000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c8585a18> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"arthas-NettyHttpTelnetBootstrap-3-2" #53 daemon prio=5 os_prio=0 tid=0x00007f4f88796800 nid=0xb84d runnable [0x00007f4f70641000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
at sun.nio.ch.SelectorImpl.lockAndDoSelect(SelectorImpl.java:86)
- locked <0x00000000c85cbed8> (a com.alibaba.arthas.deps.io.netty.channel.nio.SelectedSelectionKeySet)
- locked <0x00000000c85cbec8> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000c85cbe80> (a sun.nio.ch.EPollSelectorImpl)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:97)
at sun.nio.ch.SelectorImpl.select(SelectorImpl.java:101)
at com.alibaba.arthas.deps.io.netty.channel.nio.SelectedSelectionKeySetSelector.select(SelectedSelectionKeySetSelector.java:68)
at com.alibaba.arthas.deps.io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:813)
at com.alibaba.arthas.deps.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:460)
at com.alibaba.arthas.deps.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:995)
at com.alibaba.arthas.deps.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at com.alibaba.arthas.deps.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
"arthas-UserStat" #51 daemon prio=9 os_prio=0 tid=0x00007f4f60527800 nid=0xb83f waiting on condition [0x00007f4f5818a000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c85cc408> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"arthas-session-manager" #50 daemon prio=9 os_prio=0 tid=0x00007f4f60520000 nid=0xb83c waiting on condition [0x00007f4f5828b000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000c85ea4a8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1093)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
生产环境下的定位与分析
内存溢出
编写内存溢出代码,模拟内存溢出场景
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<>();
while (true) {
arrayList.add(UUID.randomUUID().toString());
}
}
设置JVM初始堆与最大堆的大小,以及当发生内存溢出时,生成一个dump文件
-Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
IDEA添加JVM参数并执行代码
将会生成一个java_pid16952.hprof
类似文件
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid16952.hprof ...
Heap dump file created [10500212 bytes in 0.026 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.String.substring(String.java:1933)
at java.util.UUID.digits(UUID.java:386)
at java.util.UUID.toString(UUID.java:379)
at com.example.demo.job.Test.main(Test.java:10)
导入到MAT工具中进行分析,分析给出了可能出现内存溢出的原因:有89.74%的内存由Object[]数组占有
进入Details查看详情,轻松发现原因:java.util.ArrayList @ 0xff788a18
集合中存储了大量字符串
死锁问题
在生产环境看到的是部署的程序没有任何反应,就很可能是发生了死锁问题,此时可以借助jstack进行分析
编写代码,模拟死锁场景
public class TestDeadLock {
private static Object lock1 = new Object();
private static Object lock2 = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock1) {
System.out.println("Thread1成功获取lock1锁");
try {
// 停顿2秒,让Thread2线程拿到lock2的锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread1成功获取lock2锁");
}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
System.out.println("Thread2成功获取lock2锁");
try {
// 停顿2秒,让Thread1线程拿到lock1的锁
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("Thread2成功获取lock1锁");
}
}
}).start();
}
}
出现死锁问题:
已连接到目标 VM, 地址: ''127.0.0.1:4150',传输: '套接字''
Thread1成功获取lock1锁
Thread2成功获取lock2锁
使用jstack进行分析
D:\>jps
12112
18736 TestDeadLock
7584 RemoteMavenServer36
16116 Launcher
17784 jar
20088
21448 Jps
D:\>jstack 18736
2022-10-13 23:03:17
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.271-b09 mixed mode):
"DestroyJavaVM" #16 prio=5 os_prio=0 tid=0x0000025e51097800 nid=0x2a10 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Thread-1" #15 prio=5 os_prio=0 tid=0x0000025e6d65e000 nid=0x4ce0 waiting for monitor entry [0x000000d05c7ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.demo.excel.TestDeadLock.lambda$main$1(TestDeadLock.java:33)
- waiting to lock <0x0000000776245d98> (a java.lang.Object)
- locked <0x0000000776245da8> (a java.lang.Object)
at com.example.demo.excel.TestDeadLock$$Lambda$2/1967205423.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0" #14 prio=5 os_prio=0 tid=0x0000025e6d65d000 nid=0x4bd0 waiting for monitor entry [0x000000d05c6ff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.example.demo.excel.TestDeadLock.lambda$main$0(TestDeadLock.java:18)
- waiting to lock <0x0000000776245da8> (a java.lang.Object)
- locked <0x0000000776245d98> (a java.lang.Object)
at com.example.demo.excel.TestDeadLock$$Lambda$1/1911006827.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #13 daemon prio=9 os_prio=0 tid=0x0000025e6d30f000 nid=0x4e04 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #12 daemon prio=9 os_prio=2 tid=0x0000025e6d30e000 nid=0x4b80 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #11 daemon prio=9 os_prio=2 tid=0x0000025e6d30d800 nid=0x4978 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #10 daemon prio=9 os_prio=2 tid=0x0000025e6d303000 nid=0x4c68 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #9 daemon prio=9 os_prio=2 tid=0x0000025e6d2ff000 nid=0x34b0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Command Reader" #8 daemon prio=10 os_prio=0 tid=0x0000025e6d2ee000 nid=0x4dd0 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Event Helper Thread" #7 daemon prio=10 os_prio=0 tid=0x0000025e6d2eb000 nid=0xc88 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"JDWP Transport Listener: dt_socket" #6 daemon prio=10 os_prio=0 tid=0x0000025e6d2e1000 nid=0x4c40 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000025e6d2c9000 nid=0x466c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000025e6b05e800 nid=0x1d44 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000025e5111e000 nid=0x4d4c in Object.wait() [0x000000d05bafe000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000775f08ee0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x0000000775f08ee0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000025e5111d000 nid=0x1a34 in Object.wait() [0x000000d05b9ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x0000000775f06c00> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x0000000775f06c00> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=2 tid=0x0000025e6b012000 nid=0x4028 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000025e510ad800 nid=0x450c runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000025e510af800 nid=0x4d60 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000025e510b1000 nid=0x47e8 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000025e510b2800 nid=0x48f4 runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000025e510b4800 nid=0x4e2c runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000025e510b5800 nid=0x4bbc runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000025e510b8800 nid=0x4fa4 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000025e510b9800 nid=0x491c runnable
"GC task thread#8 (ParallelGC)" os_prio=0 tid=0x0000025e510ba800 nid=0x4b40 runnable
"GC task thread#9 (ParallelGC)" os_prio=0 tid=0x0000025e510bb800 nid=0x45b8 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x0000025e6d417800 nid=0x184c waiting on condition
JNI global references: 2296
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x0000025e6b03f458 (object 0x0000000776245d98, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x0000025e6b0434f8 (object 0x0000000776245da8, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.example.demo.excel.TestDeadLock.lambda$main$1(TestDeadLock.java:33)
- waiting to lock <0x0000000776245d98> (a java.lang.Object)
- locked <0x0000000776245da8> (a java.lang.Object)
at com.example.demo.excel.TestDeadLock$$Lambda$2/1967205423.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at com.example.demo.excel.TestDeadLock.lambda$main$0(TestDeadLock.java:18)
- waiting to lock <0x0000000776245da8> (a java.lang.Object)
- locked <0x0000000776245d98> (a java.lang.Object)
at com.example.demo.excel.TestDeadLock$$Lambda$1/1911006827.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
在输出的信息中,提示:
Found 1 deadlock.
,发现1个死锁。
主要看这段代码:
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.example.demo.excel.TestDeadLock.lambda$main$1(TestDeadLock.java:33)
- waiting to lock <0x0000000776245d98> (a java.lang.Object)
- locked <0x0000000776245da8> (a java.lang.Object)
at com.example.demo.excel.TestDeadLock$$Lambda$2/1967205423.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Thread-0":
at com.example.demo.excel.TestDeadLock.lambda$main$0(TestDeadLock.java:18)
- waiting to lock <0x0000000776245da8> (a java.lang.Object)
- locked <0x0000000776245d98> (a java.lang.Object)
at com.example.demo.excel.TestDeadLock$$Lambda$1/1911006827.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
Thread-1获取了 <0x0000000776245da8> 锁,等待获取 <0x0000000776245d98>这个锁
Thread-0获取了 <0x0000000776245d98>锁,等待获取 <0x0000000776245da8> 这个锁
可视化GC日志分析工具
GC日志
通过配置GC日志输入参数可以打印GC日志信息,这些信息不够直观,可以使用第三方日志分析工具进行查看。
GC日志输入参数:
‐XX:+PrintGC 输出GC日志
‐XX:+PrintGCDetails 输出GC的详细日志
‐XX:+PrintGCTimeStamps 输出GC的时间戳
‐XX:+PrintGCDateStamps 输出GC的时间戳
‐XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息
‐Xloggc:./gc.log 日志文件的输出路径
GC日志分析
GC Easy是一个在线的可视化、功能强大、使用简单的工具。
官网:https://gceasy.io
上传一个gc日志文件分析,得出如下类似分析结果: