JVM之调优相关工具命令的使用

生活中,最使人疲惫的往往不是道路的遥远,而是心中的郁闷;最使人痛苦的往往不是生活的不幸,而是希望的破灭;最使人颓废的往往不是前途的坎坷,而是自信的丧失;最使人绝望的往往不是挫折的打击,而是心灵的死亡。所以我们要有自己的梦想,让梦想的星光指引着我们走出落漠,走出惆怅,带着我们走进自己的理想。

导读:本篇文章讲解 JVM之调优相关工具命令的使用,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

常用工具命令

概览

命令 描述
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
-gc
-gccapacity
-gccause
-gcmetacapacity
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcutil
-printcompilation

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日志文件分析,得出如下类似分析结果:
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/136868.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!