JVM故障處理工具,使用總結

小傅哥發表於2021-01-14


作者:小傅哥
部落格:https://bugstack.cn

沉澱、分享、成長,讓自己和他人都能有所收穫!?

一、前言

用都用不到怎麼學?

沒有場景、沒有訴求,怎麼學習這些似乎用不上知識點。

其實最好的方式就是歸納、整理、實踐、輸出,一套組合拳下來,你就掌握了這個系列的知識了。

但在當前階段可能真的用不上,JVM是一個穩定服務,哪能天天出問題,哪需要你老排查。又不是像你寫的程式碼那樣!

可是知識的學習就是把你墊基到更高層次後,才有機會接觸更有意思的工作和技術創新。如果只是單純的學幾個指令,其實並沒有多有意思。但讓你完成一套全鏈路監控,裡面需要含有一次方法呼叫的整體耗時、執行路徑、引數資訊、異常結果、GC次數、堆疊資料、分代內容等等的時候,那麼你的知識儲備夠開發一個這樣的系統嗎?

好,先上圖看看本文要講啥,再跟著小傅哥的步伐往下走。

JVM 故障處理工具

二、面試題

謝飛機,小記!,週末休息在家無聊,把已經上灰了的JVM虛擬機器學習翻出來。

謝飛機:呱...呱...,喂大哥,這個,這個JVM虛擬機器看啥呀。

面試官:看啥?不知道從哪開始?嗯,那你從問題點下手!

謝飛機:啥問題點呢,我就是不知道自己不會啥,也不知道問你啥。

面試官:啊!那我問你個,怎麼通過JVM故障處理工具,檢視JVM啟動時引數都配置了什麼呢?

謝飛機:這個!?不道呀!

面試官:那你熟悉的監控指令都有啥,如果問你堆記憶體統計如何統計,你可知曉!?

謝飛機:也不知道,哈哈哈,好像知道要去看啥了!

面試官:去吧,帶著問題看,看完整理出來!

三、基礎故障處理工具

1. jps 虛擬機器程式狀況

jps(JVM Process Status Tool),它的功能與ps命令類似,可以列出正在執行的虛擬機器程式,並顯示虛擬機器執行主類(Main Class,main()函式所在的類)名稱以及這些程式的本地虛擬機器唯一ID(Local Virtual Machine Identifier,LVMID),類似於 ps -ef | grep java 的功能。

這小傢伙雖然不大,功能又單一。但可以說基本你用其他命令都得先用它,來查詢到LVMID來確定要監控的是哪個虛擬機器程式。

命令格式

jps [ options ] [ hostid ]

  • options:選項、引數,不同的引數可以輸出需要的資訊
  • hostid:遠端檢視

選項列表

選項 描述
-q 只輸出程式ID,忽略主類資訊
-l 輸出主類全名,或者執行JAR包則輸出路徑
-m 輸出虛擬機器程式啟動時傳遞給主類main()函式的引數
-v 輸出虛擬機器程式啟動時的JVM引數

1.1 jps -q,只列出程式ID

E:\itstack\git\github.com\interview>jps -q
104928
111552
26852
96276
59000
8460
76188

1.2 jps -l,輸出當前執行類全稱

E:\itstack\git\github.com\interview>jps -l
111552 org/netbeans/Main
26852
96276 org.jetbrains.jps.cmdline.Launcher
59000
62184 sun.tools.jps.Jps
8460 org/netbeans/Main
76188 sun.tools.jstatd.Jstatd
  • 用這個命令輸出的內容就清晰多了,-l 也是非常常用的一個引數選項。

1.3 jps -m,列出傳給main()函式的引數

E:\itstack\git\github.com\interview>jps -m
111552 Main --branding visualvm --cachedir C:\Users\xiaofuge\AppData\Local\VisualVM\Cache/8u131 --openid 3041391569375200
26852
96276 Launcher C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/plugins/java/lib/javac2.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/plugins/java/lib/aether-api-1.1.0.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/lib/jna-platform.jar;C:/Program Fi
les/JetBrains/IntelliJ IDEA 2019.3.1/lib/guava-27.1-jre.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/lib/httpclient-4.5.10.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/lib/forms-1.1-preview.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/plu
gins/java/lib/aether-connector-basic-1.1.0.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/plugins/java/lib/maven-model-builder-3.3.9.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/lib/jps-model.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/plu
gins/java/lib/maven-model-3.3.9.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/plugins/java/lib/aether-impl-1.1.0.jar;C:/Program Files/JetBrains/IntelliJ IDEA 2019.3.1/lib/gson-2.8.5.jar;C:/Program File
59000
16844 Jps -m
8460 Main --branding visualvm --cachedir C:\Users\xiaofuge\AppData\Local\VisualVM\Cache/8u131 --openid 3041414336579200
76188 Jstatd

1.4 jps -v,輸出虛擬機器程式啟動時JVM引數[-Xms24m -Xmx256m]

E:\itstack\git\github.com\interview>jps -v
111552 Main -Xms24m -Xmx256m -Dsun.jvmstat.perdata.syncWaitMs=10000 -Dsun.java2d.noddraw=true -Dsun.java2d.d3d=false -Dnetbeans.keyring.no.master=true -Dplugin.manager.install.global=false --add-exports=java.desktop/sun.awt=ALL-UNNAMED --add-exports=jdk.jvmstat/sun
.jvmstat.monitor.event=ALL-UNNAMED --add-exports=jdk.jvmstat/sun.jvmstat.monitor=ALL-UNNAMED --add-exports=java.desktop/sun.swing=ALL-UNNAMED --add-exports=jdk.attach/sun.tools.attach=ALL-UNNAMED --add-modules=java.activation -XX:+IgnoreUnrecognizedVMOptions -Djdk.
home=C:/Program Files/Java/jdk1.8.0_161 -Dnetbeans.home=C:\Program Files\Java\jdk1.8.0_161\lib\visualvm\platform -Dnetbeans.user=C:\Users\xiaofuge1\AppData\Roaming\VisualVM\8u131 -Dnetbeans.default_userdir_root=C:\Users\xiaofuge1\AppData\Roaming\VisualVM -XX:+H
eapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\xiaofuge1\AppData\Roaming\VisualVM\8u131\var\log\heapdump.hprof -Dsun.awt.keepWorkingSetOnMinimize=true -Dnetbeans.dirs=C:\Program Files\Java\jdk1.8.0_161\lib\visualvm\visualvm;C:\Program
59000  -Dfile.encoding=UTF-8 -Xms128m -Xmx1024m -XX:MaxPermSize=256m
76188 Jstatd -Denv.class.path=.;C:\Program Files\Java\jre1.8.0_161\lib;C:\Program Files\Java\jre1.8.0_161\lib\tool.jar; -Dapplication.home=C:\Program Files\Java\jdk1.8.0_161 -Xms8m -Djava.security.policy=jstatd.all.policy

1.5 jps -lv 127.0.0.1,輸出遠端機器資訊

jps 連結遠端輸出JVM資訊,需要註冊RMI,否則會報錯 RMI Registry not available at 127.0.0.1

註冊RMI開啟 jstatd 在你的 C:\Program Files\Java\jdk1.8.0_161\bin 目錄下新增名稱為 jstatd.all.policy 的檔案。無其他字尾

jstatd.all.policy 檔案內容如下:

grant codebase "file:${java.home}/../lib/tools.jar" {
   permission java.security.AllPermission;
};

新增好配置檔案後,在 bin 目錄下注冊新增的 jstatd.all.policy 檔案:C:\Program Files\Java\jdk1.8.0_161\bin>jstatd -J-Djava.security.policy=jstatd.all.policy

順利的話現在就可以檢視原創機器JVM資訊了,如下:

E:\itstack\git\github.com\interview>jps -l 127.0.0.1
111552 org/netbeans/Main
26852
96276 org.jetbrains.jps.cmdline.Launcher
36056 sun.tools.jps.Jps
59000
8460 org/netbeans/Main
76188 sun.tools.jstatd.Jstatd
  • 也可以組合使用 jps 的選項引數,比如:jps -lm 127.0.0.1

2. jcmd 虛擬機器診斷命令

jcmd,是從jdk1.7開始新發布的 JVM 相關資訊診斷工具,可以用它來匯出堆和執行緒資訊、檢視Java程式、執行GC、還可以進行取樣分析(jmc 工具的飛行記錄器)。注意其使用條件是隻能在被診斷的JVM同臺sever上,並且具有相同的使用者和組(user and group).

命令格式

jcmd <pid | main class> <command ...|PerfCounter.print|-f file>

  • pid,接收診斷命令請求的程式ID
    • main class,接收診斷命令請求的程式main類。
  • command,接收診斷命令請求的程式main類。
  • PerfCounter.print,列印目標 Java 程式上可用的效能計數器。
  • -f file,從檔案file中讀取命令,然後在目標Java程式上呼叫這些命令。
  • -l,檢視所有程式列表資訊。
  • -h、-help,檢視幫助資訊。

2.1 jcmd pid VM.flags,檢視JVM啟動引數

E:\itstack\git\github.com\interview>jcmd 111552 VM.flags
111552:
-XX:CICompilerCount=4 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=C:\Users\xiaofuge1\AppData\Roaming\VisualVM\8u131\var\log\heapdump.hprof -XX:+IgnoreUnrecognizedVMOptions -XX:InitialHeapSize=25165824 -XX:MaxHeapSize=268435456 -XX:MaxNewSize=89128960 -XX:Min
HeapDeltaBytes=524288 -XX:NewSize=8388608 -XX:OldSize=16777216 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC

2.2 jcmd pid VM.uptime,檢視JVM執行時長

E:\itstack\git\github.com\interview>jcmd 111552 VM.uptime
111552:
583248.912 s

2.3 jcmd pid PerfCounter.print,檢視JVM效能相關引數

E:\itstack\git\github.com\interview>jcmd 111552 PerfCounter.print
111552:
java.ci.totalTime=56082522
java.cls.loadedClasses=5835
java.cls.sharedLoadedClasses=0
java.cls.sharedUnloadedClasses=0
java.cls.unloadedClasses=37
...

2.4 jcmd pid GC.class_histogram,檢視系統中類的統計資訊

E:\itstack\git\github.com\interview>jcmd 111552 GC.class_histogram
111552:

 num     #instances         #bytes  class name
----------------------------------------------
   1:         50543        3775720  [C
   2:          3443        2428248  [I
   3:         50138        1203312  java.lang.String
   4:         25351         811232  java.util.HashMap$Node
   5:          6263         712208  java.lang.Class
   6:          3134         674896  [B
   7:          6687         401056  [Ljava.lang.Object;
   8:          2468         335832  [Ljava.util.HashMap$Node;

2.5 jcmd pid Thread.print,檢視執行緒堆疊資訊

E:\itstack\git\github.com\interview>jcmd 111552 Thread.print
111552:
2021-01-10 23:31:13
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.161-b12 mixed mode):

"Computes values in handlers" #52 daemon prio=5 os_prio=0 tid=0x0000000019839000 nid=0x16014 waiting for monitor entry [0x0000000026bce000]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at com.sun.tools.visualvm.core.model.ModelFactory.getModel(ModelFactory.java:76)
        - waiting to lock <0x00000000f095bcf8> (a com.sun.tools.visualvm.jvmstat.application.JvmstatApplication)
        at com.sun.tools.visualvm.application.jvm.JvmFactory.getJVMFor(JvmFactory.java:45)
        at com.sun.tools.visualvm.application.options.Open.openApplication(Open.java:108)
        at com.sun.tools.visualvm.application.options.Open.process(Open.java:93)
        at org.netbeans.spi.sendopts.Option$1.process(Option.java:348)
        at org.netbeans.api.sendopts.CommandLine.process(CommandLine.java:278)
        at org.netbeans.modules.sendopts.HandlerImpl.execute(HandlerImpl.java:23)
        at org.netbeans.modules.sendopts.Handler.cli(Handler.java:30)
        at org.netbeans.CLIHandler.notifyHandlers(CLIHandler.java:195)
        at org.netbeans.core.startup.CLICoreBridge.cli(CLICoreBridge.java:43)
        at org.netbeans.CLIHandler.notifyHandlers(CLIHandler.java:195)
        at org.netbeans.CLIHandler$Server$1ComputingAndNotifying.run(CLIHandler.java:1176)

2.6 jcmd pid VM.system_properties,檢視JVM系統引數

E:\itstack\git\github.com\interview>jcmd 111552 VM.system_properties
111552:
#Sun Jan 13 23:33:19 CST 2021
java.vendor=Oracle Corporation
netbeans.user=C\:\\Users\\xiaofuge1\\AppData\\Roaming\\VisualVM\\8u131
sun.java.launcher=SUN_STANDARD
sun.management.compiler=HotSpot 64-Bit Tiered Compilers
netbeans.autoupdate.version=1.23
os.name=Windows 10

2.7 jcmd pid GC.heap_dump 路徑,匯出heap dump檔案

E:\itstack\git\github.com\interview>jcmd 111552 GC.heap_dump C:\Users\xiaofuge1\Desktop\_dump_0110
111552:
Heap dump file created
  • 匯出的檔案需要配合 jvisualvm 檢視

2.8 jcmd pid help,列出可執行操作

E:\itstack\git\github.com\interview>jcmd 111552 help
111552:
The following commands are available:
JFR.stop
JFR.start
JFR.dump
JFR.check

2.9 jcmd pid help JFR.stop,檢視命令使用

E:\itstack\git\github.com\interview>jcmd 111552 help JFR.stop
111552:
JFR.stop
Stops a JFR recording

Impact: Low

Permission: java.lang.management.ManagementPermission(monitor)

Syntax : JFR.stop [options]

Options: (options must be specified using the <key> or <key>=<value> syntax)
        name : [optional] Recording name,.e.g \"My Recording\" (STRING, no default value)
        recording : [optional] Recording number, see JFR.check for a list of available recordings (JLONG, -1)
        discard : [optional] Skip writing data to previously specified file (if any) (BOOLEAN, false)
        filename : [optional] Copy recording data to file, e.g. \"C:\Users\user\My Recording.jfr\" (STRING, no default value)
        compress : [optional] GZip-compress "filename" destination (BOOLEAN, false)

3. jinfo Java配置資訊工具

jinfo(Configuration Info for Java),實時檢視和調整JVM的各項引數。

在上面講到 jps -v 指令時,可以看到它把虛擬機器啟動時顯式的引數列表都列印出來了,但如果想更加清晰的看具體的一個引數或者想知道未被顯式指定的引數時,就可以通過 jinfo -flag 來查詢了。

命令格式

jinfo [ option ] pid

使用方式

E:\itstack\git\github.com\interview>jinfo -flag MetaspaceSize 111552
-XX:MetaspaceSize=21807104

E:\itstack\git\github.com\interview>jinfo -flag MaxMetaspaceSize 111552
-XX:MaxMetaspaceSize=18446744073709486080

E:\itstack\git\github.com\interview>jinfo -flag HeapDumpPath 111552
-XX:HeapDumpPath=C:\Users\xiaofuge\AppData\Roaming\VisualVM\8u131\var\log\heapdump.hprof
  • 各種JVM引數你都可以去查詢,這樣更加方便的只把你要的顯示出來。

4. jstat 收集虛擬機器執行資料

jstat(JVM Statistics Monitoring Tool),用於監視虛擬機器各種執行狀態資訊。它可以檢視本地或者遠端虛擬機器程式中,類載入、記憶體、垃圾收集、即時編譯等執行時資料。

命令格式

jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

  • vmid:如果是檢視遠端機器,需要按照此格式:[protocol:][//]lvmid[@hostname[:port]/servername]
  • interval和count,表示查詢間隔和次數,比如每隔1000毫秒查詢一次程式ID的gc收集情況,每次查詢5次。jstat -gc 111552 1000 5

選項列表

選項 描述
-class 監視類載入、解除安裝數量、總空間以及類裝載所耗費時長
-gc 監視 Java 堆情況,包括Eden區、2個 Survivor區、老年代、永久代或者jdk1.8元空間等,容量、已用空間、垃圾收集時間合計等資訊
-gccapacity 監視內容與-gc基本一致,但輸出主要關注 Java 堆各個區域使用到的最大、最小空間
-gcutil 監視內容與-gc基本相同,但輸出主要關注已使用空間佔總空間的百分比
-gccause 與 -gcutil 功能一樣,但是會額外輸出導致上一次垃圾收集產生的原因
-gcnew 監視新生代垃圾收集情況
-gcnewcapacity 監視內容與 -gcnew 基本相同,輸出主要關注使用到的最大、最小空間
-gcold 監視老年代垃圾收集情況
-gcoldcapacity 監視內容與 -gcold 基本相同,輸出主要關注使用到的最大、最小空間
-compiler 輸出即時編譯器編譯過的方法、耗時等資訊
-printcompilation 輸出已經被即時編譯的方法
-gcpermcapacity jdk1.7 及以下,永久代空間統計
-gcmetacapacity jdk1.8,元空間統計
  • jstat 的監視選項還是非常多的,但最常用的主要有上面這些。

4.01 jstat -class,類載入統計

E:\itstack\git\github.com\interview>jstat -class 111552
Loaded  Bytes  Unloaded  Bytes     Time
  5835 12059.6       37    53.5       3.88
  • Loaded,載入class的數量
  • Bytes:所佔用空間大小
  • Unloaded:未載入數量
  • Bytes:未載入佔用空間
  • Time:時間

4.02 jstat -compiler,編譯統計

E:\itstack\git\github.com\interview>jstat -compiler 111552
Compiled Failed Invalid   Time   FailedType FailedMethod
    3642      0       0     5.61          0
  • Compiled:編譯數量
  • Failed:失敗數量
  • Invalid:不可用數量
  • Time:時間
  • FailedType:失敗型別
  • FailedMethod:失敗方法

4.03 jstat -gc,垃圾回收統計

E:\itstack\git\github.com\interview>jstat -gc 111552
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
1024.0 512.0   0.0    0.0   77312.0    35.1    39424.0    13622.9   37120.0 34423.3 5376.0 4579.4     60    0.649  52      3.130    3.779
  • S0C、S1C,第一個和第二個倖存區大小
  • S0U、S1U,第一個和第二個倖存區使用大小
  • EC、EU,伊甸園的大小和使用
  • OC、OU,老年代的大小和使用
  • MC、MU,方法區的大小和使用
  • CCSC、CCSU,壓縮類空間大小和使用
  • YGC、YGCT,年輕代垃圾回收次數和耗時
  • FGC、FGCT,老年代垃圾回收次數和耗時
  • GCT,垃圾回收總耗時

4.04 jstat -gccapacity,堆記憶體統計

E:\itstack\git\github.com\interview>jstat -gccapacity 111552
 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC
  8192.0  87040.0  80384.0 1024.0  512.0  77312.0    16384.0   175104.0    39424.0    39424.0      0.0 1081344.0  37120.0      0.0 1048576.0   5376.0     60    52
  • NGCMN、NGCMX,新生代最小和最大容量
  • NGC,當前新生代容量
  • S0C、S1C,第一和第二倖存區大小
  • EC,伊甸園區的大小
  • OGCMN、OGCMX,老年代最小和最大容量
  • OGC、OC,當前老年代大小
  • MCMN、MCMX,後設資料空間最小和最大容量
  • MC,當前元空間大小
  • CCSMN、CCSMX,壓縮類最小和最大空間
  • YGC,年輕代GC次數
  • FGC,老年代GC次數

4.05 jstat -gcnewcapacity,新生代記憶體統計

E:\itstack\git\github.com\interview>jstat -gcnewcapacity 111552
  NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC
    8192.0    87040.0    80384.0  28672.0   1024.0  28672.0    512.0    86016.0    77312.0    60    52
  • NGCMN、NGCMX,新生代最小和最大容量
  • NGC,當前新生代容量
  • S0CMX,最大幸存0區大小
  • S0C,當前倖存0區大小
  • S1CMX,最大幸存1區大小
  • S1C,當前倖存1區大小
  • ECMX,最大伊甸園區大小
  • EC,當前伊甸園區大小
  • YGC,年輕代垃圾回收次數
  • FGC,老年代回收次數

4.06 jstat -gcnew,新生代垃圾回收統計

E:\itstack\git\github.com\interview>jstat -gcnew 111552
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT
1024.0  512.0    0.0    0.0  3  15  512.0  77312.0     70.2     60    0.649
  • S0C、S1C,第一和第二倖存區大小
  • S0U、S1U,第一和第二倖存區使用
  • TT,物件在新生代存活的次數
  • MTT,物件在新生代存活的最大次數
  • DSS:期望的倖存區大小
  • EC,伊甸園區的大小
  • EU,伊甸園區的使用
  • YGC,年輕代垃圾回收次數
  • YGCT,年輕代垃圾回收消耗時間

4.07 jstat -gcold,老年代垃圾回收統計

E:\itstack\git\github.com\interview>jstat -gcold 111552
   MC       MU      CCSC     CCSU       OC          OU       YGC    FGC    FGCT     GCT
 37120.0  34423.3   5376.0   4579.4     39424.0     13622.9     60    52    3.130    3.779
  • MC、MU,方法區的大小和使用
  • CCSC、CCSU,壓縮類空間大小和使用
  • OC、OU,老年代大小和使用
  • YGC,年輕代垃圾回收次數
  • FGC,老年代垃圾回收次數
  • FGCT,老年代垃圾回收耗時
  • GCT,垃圾回收總耗時

4.08 jstat -gcoldcapacity,老年代記憶體統計

E:\itstack\git\github.com\interview>jstat -gcoldcapacity 111552
   OGCMN       OGCMX        OGC         OC       YGC   FGC    FGCT     GCT
    16384.0    175104.0     39424.0     39424.0    60    52    3.130    3.779
  • OGCMN、OGCMX,老年代最小和最大容量
  • OGC,當前老年代大小
  • OC,老年代大小
  • YGC,年輕代垃圾回收次數
  • FGC,老年代垃圾回收次數
  • FGCT,老年代垃圾回收耗時
  • GCT,垃圾回收消耗總耗時

4.09 jstat -gcmetacapacity,元空間統計

E:\itstack\git\github.com\interview>jstat -gcmetacapacity 111552
   MCMN       MCMX        MC       CCSMN      CCSMX       CCSC     YGC   FGC    FGCT     GCT
       0.0  1081344.0    37120.0        0.0  1048576.0     5376.0    60    52    3.130    3.779
  • MCMN、MCMX,元空間最小和最大容量
  • MC,當前後設資料空間大小
  • CCSMN、CCSMX,壓縮類最小和最大空間
  • CCSC,壓縮類空間大小
  • YGC,年輕代垃圾回收次數
  • FGC,老年代垃圾回收次數
  • FGCT,老年代垃圾回收耗時
  • GCT,垃圾回收消耗總耗時

4.10 jstat -gcutil,垃圾回收統計

E:\itstack\git\github.com\interview>jstat -gcutil 111552
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00   0.00   0.09  34.55  92.74  85.18     60    0.649    52    3.130    3.779
  • S0、S1、倖存1區和2區,當前使用佔比
  • E,伊甸園區使用佔比
  • O,老年代區使用佔比
  • M,後設資料區使用佔比
  • CCS,壓縮類使用佔比
  • YGC,年輕代垃圾回收次數
  • FGC,老年代垃圾回收次數
  • FGCT,老年代垃圾回收耗時
  • GCT,垃圾回收消耗總耗時

4.11 jstat -printcompilation,JVM編譯方法統計

E:\itstack\git\github.com\interview>jstat -printcompilation 111552
Compiled  Size  Type Method
    3642      9    1 java/io/BufferedWriter min
  • Compiled:最近編譯方法的數量
  • Size:最近編譯方法的位元組碼數量
  • Type:最近編譯方法的編譯型別
  • Method:方法名標識

5. jmap 記憶體對映工具

jmap(Memory Map for Java),用於生成堆轉儲快照(heapdump檔案)。

jmap 的作用除了獲取堆轉儲快照,還可以查詢finalize執行佇列、Java 堆和方法區的詳細資訊。

命令格式

jmap [ option ] pid

  • option:選項引數
  • pid:需要列印配置資訊的程式ID
  • executable:產生核心dump的Java可執行檔案
  • core:需要列印配置資訊的核心檔案
  • server-id:可選的唯一id,如果相同的遠端主機上執行了多臺除錯伺服器,用此選項引數標識伺服器
  • remote server IP or hostname: 遠端除錯伺服器的IP地址或主機名

選項列表

選項 描述
-dump 生成 Java 堆轉儲快照。
-finalizerinfo 顯示在F-Queue中等待Finalizer執行緒執行finalize方法的物件。Linux平臺
-heap 顯示 Java 堆詳細資訊,比如:用了哪種回收器、引數配置、分代情況。Linux平臺
-histo 顯示堆中物件統計資訊,包括類、例項數量、合計容量
-permstat 顯示永久代記憶體狀態,jdk1.7,永久代
-F 當虛擬機器程式對 -dump 選項沒有響應式,可以強制生成快照。Linux平臺

5.1 jmap,列印共享物件對映

E:\itstack\git\github.com\interview>jmap 111552
Attaching to process ID 111552, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.161-b12
0x000000005b4a0000      1632K   C:\Program Files\Java\jdk1.8.0_161\jre\bin\awt.dll
0x000000005b8c0000      264K    C:\Program Files\Java\jdk1.8.0_161\jre\bin\t2k.dll
0x000000005b910000      284K    C:\Program Files\Java\jdk1.8.0_161\jre\bin\fontmanager.dll
0x000000005b960000      224K    C:\Program Files\Java\jdk1.8.0_161\jre\bin\splashscreen.dll
0x000000005b9a0000      68K     C:\Program Files\Java\jdk1.8.0_161\jre\bin\nio.dll

5.2 jmap -heap,堆詳細資訊

E:\itstack\git\github.com\interview>jmap -heap 111552
Attaching to process ID 111552, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.161-b12

using thread-local object allocation.
Parallel GC with 8 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 268435456 (256.0MB)
   NewSize                  = 8388608 (8.0MB)
   MaxNewSize               = 89128960 (85.0MB)
   OldSize                  = 16777216 (16.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

5.3 jmap -clstats,列印載入類

E:\itstack\git\github.com\interview> jmap -clstats 111552
Attaching to process ID 111552, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.161-b12
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>     3779    6880779   null          live    <internal>
0x00000000f03853b8      57      132574  0x00000000f031aac8      live    org/netbeans/StandardModule$OneModuleClassLoader@0x00000001001684f0
0x00000000f01b9b98      0       0       0x00000000f031aac8      live    org/netbeans/StandardModule$OneModuleClassLoader@0x00000001001684f0
0x00000000f005b280      0       0       0x00000000f031aac8      live    java/util/ResourceBundle$RBClassLoader@0x00000001000c6ae0
0x00000000f01dfa98      0       0       0x00000000f031aac8      live    org/netbeans/StandardModule$OneModuleClassLoader@0x00000001001684f0
0x00000000f01ec518      79      252894  0x00000000f031aac8      live    org/netbeans/StandardModule$OneModuleClassLoader@0x00000001001684f0

5.4 jmap -dump,堆轉儲檔案

E:\itstack\git\github.com\interview>jmap -dump:live,format=b,file=C:/Users/xiaofuge/Desktop/heap.bin 111552
Dumping heap to C:\Users\xiaofuge\Desktop\heap.bin ...
Heap dump file created

6. jhat 堆轉儲快照分析工具

jhat(JVM Heap Analysis Tool),與jmap配合使用,用於分析jmap生成的堆轉儲快照。

jhat內建了一個小型的http/web伺服器,可以把堆轉儲快照分析的結果,展示在瀏覽器中檢視。不過用途不大,基本大家都會使用其他第三方工具。

命令格式

jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [-debug <int>] [-version] [-h|-help] <file>

命令使用

E:\itstack\git\github.com\interview>jhat -port 8090 C:/Users/xiaofuge1/Desktop/heap.bin
Reading from C:/Users/xiaofuge1/Desktop/heap.bin...
Dump file created Wed Jan 13 16:53:47 CST 2021
Snapshot read, resolving...
Resolving 246455 objects...
Chasing references, expect 49 dots.................................................
Eliminating duplicate references.................................................
Snapshot resolved.
Started HTTP server on port 8090
Server is ready.

http://localhost:8090/

jhat -port 8090

7. jstack Java堆疊跟蹤工具

jstack(Stack Trace for Java),用於生成虛擬機器當前時刻的執行緒快照(threaddump、javacore)。

執行緒快照就是當前虛擬機器內每一條執行緒正在執行的方法堆疊的集合,生成執行緒快照的目的通常是定位執行緒出現長時間停頓的原因,如:執行緒死鎖、死迴圈、請求外部資源耗時較長導致掛起等。

執行緒出現聽頓時通過jstack來檢視各個執行緒的呼叫堆疊,就可以獲得沒有響應的執行緒在搞什麼鬼。

命令格式

jstack [ option ] vmid

選項引數

選項 描述
-F 當正常輸出的請求不被響應時,強制輸出執行緒堆疊
-l 除了堆疊外,顯示關於鎖的附加資訊
-m 如果呼叫的是本地方法的話,可以顯示c/c++的堆疊

命令使用

E:\itstack\git\github.com\interview>jstack 111552
2021-01-10 23:15:03
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.161-b12 mixed mode):

"Inactive RequestProcessor thread [Was:StdErr Flush/org.netbeans.core.startup.logging.PrintStreamLogger]" #59 daemon prio=1 os_prio=-2 tid=0x000000001983a800 nid=0x688 in Object.wait() [0x0000000017fbf000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:1939)
        - locked <0x00000000fab31d88> (a java.lang.Object)
  • 在驗證使用的過程中,可以嘗試寫一個死迴圈的執行緒,之後通過jstack檢視執行緒資訊。

四、視覺化故障處理工具

1. jconsole,Java監視與管理控制檯

JConsole( Java Monitoring and Management Console),是一款基於JMX( Java Manage-ment
Extensions) 的視覺化監視管理工具。

它的功能主要是對系統進行收集和引數調整,不僅可以在虛擬機器本身管理還可以開發在軟體上,是開放的服務,有相應的程式碼API呼叫。

JConsole 啟動

JConsole 啟動

JConsole 使用

JConsole 使用

2. VisualVM,多合故障處理工具

VisualVM( All-in-One Java Troubleshooting Tool),是功能最強大的執行監視和故障處理工具之一。

它除了常規的執行監視、故障處理外,還可以做效能分析等工作。因為它的通用性很強,對應用程式影響較小,所以可以直接接入到生產環境中。

VisualVM IDEA安裝

VisualVM IDEA安裝

VisualVM 使用

public static void main(String[] args) throws InterruptedException {
    
    Thread.sleep(5000);
    ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean();
    while (true) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(MetaSpaceOomMock.class);
        enhancer.setCallbackTypes(new Class[]{Dispatcher.class, MethodInterceptor.class});
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                return 1;
            }
            @Override
            public boolean equals(Object obj) {
                return super.equals(obj);
            }
        });
        System.out.println(enhancer.createClass().getName() + loadingBean.getTotalLoadedClassCount() + loadingBean.getLoadedClassCount() + loadingBean.getUnloadedClassCount());
    }
}

記得調整元空間大小

-XX:MetaspaceSize=8m
-XX:MaxMetaspaceSize=80m
-Djava.rmi.server.hostname=127.0.0.1
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=7397
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
  • 我們就監測這段讓元空間溢位的程式碼,java.lang.OutOfMemoryError: Metaspace

監控結果

VisualVM,監控結果

五、總結

  • 本文也是小傅哥在學習《深入理解Java虛擬機器》過程中的一個總結,這裡包括了很多常用的指令,通過這些指令的學習我們也大概會知道JVM都給我們提供了什麼樣的監控資訊。
  • 其實實際的業務使用中很少通過指令去監控JVM而是有一整套的非入侵全鏈路監控,在監控服務裡與之方法呼叫時的JVM一併監控,可以讓研發人員更快速的排查問題。但這些工具的實現依然是需要這些基礎,在有了基礎的知識掌握後,可以更好多使用工具。
  • 程式設計技術類知識的學習一定要實踐驗證,否則很容易忘記,也很難掌握。當你經過自己手多敲幾遍以後,就會有完全不一樣的認識。好了,加油!希望本篇文章能為你的薪資鼓鼓勁!

六、系列推薦

相關文章