目錄
- 簡介
- jmap
- clstats
- finalizerinfo
- histo
- dump
- jhat
- 總結
簡介
我們在寫代碼的過程中,經常會遇到記憶體洩露的問題,比如某個集合中的對象沒有被回收,或者記憶體出現不明原因的增長。這些都是需要我們來定位的問題,我們可以使用jmap和jhat來對java程式中的記憶體對象進行分析。
jmap(Java Memory Map)是JDK自帶的工具,用來将某個java程式的記憶體中的資訊列印或者輸出到檔案中,然後通過jhat(Java Heap Analysis Tool)工具對輸出的檔案進行分析,進而找到可能出現的問題。
接下來進入我們的jmap和jhat之旅吧。
jmap
jmap -clstats <pid>
to connect to running process and print class loader statistics
jmap -finalizerinfo <pid>
to connect to running process and print information on objects awaiting finalization
jmap -histo[:[<histo-options>]] <pid>
to connect to running process and print histogram of java object heap
jmap -dump:<dump-options> <pid>
to connect to running process and dump java heap
jmap有下面四個可用選項:
clstats
clstats的全稱叫做class loader statistics,用輸出類加載有關的統計資訊。
舉一個例子:
jmap -clstats 8820
輸出結果如下:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5yNwgzM3QzN1MWMlZ2MygjMzYzX4MDMxYTM5EzLclDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
- Index - class的編号
- Super - 父類的編号
- InstBytes - 每個instance的bytes大小
- KlassBytes - 該class的bytes大小
- annotations - 注解大小
- CpAll - 每個class中constants, tags, cache, 和 operands的大小
- MethodCount - class中方法的個數
- Bytecodes - byte codes的大小
- MethodAll - method, CONSTMETHOD, stack map, 和 method data的大小
- ROAll - 可以放到read-only memory中的class中繼資料的大小
- RWAll - 可以放到read/write memory中的class中繼資料大小
- Total - ROAll + RWAll
- ClassName - class name
finalizerinfo
finalizerinfo列出準備finalization的對象。
jmap -finalizerinfo 8820
如果沒有對象等待被finalization,則會輸出:
No instances waiting for finalization found
histo
histo用來輸出java heap對象的直方圖。可以加一個live選項,用來輸出live的對象。
jmap -histo:live 8820
輸出結果:
num是對象的編号,instances是對象的個數,bytes是對象的大小,class name是對象的class名字。
dump
最後要講一下dump,dump用于dump整個java heap,dump可以接三個參數:
- live - dump live對象
- format=b - 以hprof的二進制模式dump
- file=filename - dump對象到檔案中
jmap -dump:live,file=dump.log 8820
這裡dump.log檔案是非常大的,用肉眼也很難分析,下面我們介紹一下jhat(Java Heap Analysis Tool)指令來對dump出來的對象進行分析。
jhat
注意,jhat從JDK9的時候已經删除了(JEP 241: Remove the jhat Tool)。現在Oracle官方推薦的分析工具是Eclipse Memory Analyzer Tool (MAT) 和 VisualVM。 這兩款工具後面有時間再詳細講解。
今天先使用JDK8中的jhat來分析一下上面dump出來的檔案。
先看下jhat的指令格式:
Usage: jhat [-stack <bool>] [-refs <bool>] [-port <port>] [-baseline <file>] [-debug <int>] [-version] [-h|-help] <file>
-J<flag> Pass <flag> directly to the runtime system. For
example, -J-mx512m to use a maximum heap size of 512MB
-stack false: Turn off tracking object allocation call stack.
-refs false: Turn off tracking of references to objects
-port <port>: Set the port for the HTTP server. Defaults to 7000
-exclude <file>: Specify a file that lists data members that should
be excluded from the reachableFrom query.
-baseline <file>: Specify a baseline object dump. Objects in
both heap dumps with the same ID and same class will
be marked as not being "new".
-debug <int>: Set debug level.
0: No debug output
1: Debug hprof file parsing
2: Debug hprof file parsing, no server
因為這個指令已經被廢棄了,這裡就不過多講解它的參數,總體來說jhap會解析dump出來的檔案,并在本地啟動一個web伺服器,我們可以通過web頁面來檢視dump出來的資料。預設情況下web伺服器的端口是7000。
jhat dump.log
Reading from dump.log...
Dump file created Mon May 11 21:13:43 CST 2020
Snapshot read, resolving...
Resolving 197989 objects...
Chasing references, expect 39 dots.......................................
Eliminating duplicate references.......................................
Snapshot resolved.
打開localhost:7000,我們可以看到首頁展示的是各個包中的類的執行個體和位址資訊:
點選首頁的類的連結,可以跳轉到類的具體資訊頁面:
類的資訊頁面包含很多資訊,包括父類,類加載器,簽名,安全域,子類,執行個體,引用等詳細資訊。
對我們分析記憶體洩露和記憶體異常等情況非常有用。
總結
本文介紹了jmap和jhat的使用。
本文作者:flydean程式那些事