jmap的使用以及記憶體溢位分析
jmap(java記憶體映像工具)
jmap(Memory Map for Java)命令用于生成堆轉儲快照(一般稱為heapdump或dump檔案),還有幾種方式獲取dump檔案:使用JVM引數選項-XX:+HeapDumpOnOutOfMemoryError引數,可以讓虛擬機在OOM例外出現之后自動生成dump檔案,通過-XX:HeapDumpPath=path 設定dump檔案路徑(有時候dump檔案比較大的時候可能無法自動匯出,這時候就需要使用jmap -dump手動匯出了);通過-XX.+HeapDumpOnCtrlBreak引數則可以使用[Ctrl]+[Break]鍵讓虛擬機生成dump檔案;或者在Linux系統下通過Kill -3命令發送行程退出信號,也能拿到dump檔案,
jmap的作用并不僅僅是為了獲取dump檔案,它還可以查詢finalize執行佇列、Java堆和永久代的詳細資訊,如空間使用率、當前用的是哪種收集器等,和jinfo命令一樣,jmap有不少功能在Windows平臺下都是受限的,除了生成dump檔案的-dump選項和用于查看每個類的實體、空間占用統計的-histo選項在所有作業系統都提供之外,其余選項都只能在Linux/Solans下使用,官方檔案地址
1.1、查看記憶體使用情況
[root@localhost /]# jmap -heap 9906
Attaching to process ID 9906, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.221-b11
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 989855744 (944.0MB)
NewSize = 20971520 (20.0MB)
MaxNewSize = 329908224 (314.625MB)
OldSize = 41943040 (40.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 18939904 (18.0625MB)
used = 5314648 (5.068443298339844MB)
free = 13625256 (12.994056701660156MB)
28.06058573475346% used
Eden Space:
capacity = 16842752 (16.0625MB)
used = 4780064 (4.558624267578125MB)
free = 12062688 (11.503875732421875MB)
28.38054018725681% used
From Space:
capacity = 2097152 (2.0MB)
used = 534584 (0.5098190307617188MB)
free = 1562568 (1.4901809692382812MB)
25.490951538085938% used
To Space:
capacity = 2097152 (2.0MB)
used = 0 (0.0MB)
free = 2097152 (2.0MB)
0.0% used
tenured generation:
capacity = 41943040 (40.0MB)
used = 36145136 (34.47068786621094MB)
free = 5797904 (5.5293121337890625MB)
86.17671966552734% used
31688 interned Strings occupying 3707776 bytes.
1.2、查看記憶體中物件數量及大小
#查看所有物件,包括活躍以及非活躍的
jmap -histo <pid> | more
#查看活躍物件
jmap -histo:live <pid> | more
[root@localhost /]# jmap -histo:live 9906 | more
num #instances #bytes class name
----------------------------------------------
1: 72627 10929400 [C
2: 12052 2445368 [I
3: 3709 1718968 [B
4: 71294 1711056 java.lang.String
5: 14306 1258928 java.lang.reflect.Method
6: 8153 922992 java.lang.Class
7: 26390 844480 java.util.HashMap$Node
8: 23271 744672 java.util.concurrent.ConcurrentHashMap$Node
9: 10490 629792 [Ljava.lang.Object;
10: 5128 536080 [Ljava.util.HashMap$Node;
#物件說明
B byte
C char
D double
F float
I int
J long
Z boolean
[陣列,如[I表示int[]
[L+類名 其他物件
1.3、將記憶體使用情況dump到檔案中
#用法:
jmap -dump:format=b,file=dumpFileName <pid>
#示例
[root@localhost /]# jmap -dump:format=b,file=/cfile/dump.dat 9906
Dumping heap to /cfile/dump.dat ...
Heap dump file created

1.4、通過jhat對dump檔案進行分析
jvm的記憶體dump到檔案中,這個檔案是一個二進制的檔案,不方便查看,可以借助于jhat工具進行查看,
#用法:
jhat -port <port> <file>
#示例
[root@localhost cfile]# jhat -port 8888 /cfile/dump.dat
Reading from /cfile/dump.dat...
Dump file created Thu Aug 19 11:31:02 CST 2021
Snapshot read, resolving...
Resolving 476416 objects...
Chasing references, expect 95 dots...............................................................................................
Eliminating duplicate references...............................................................................................
Snapshot resolved.
Started HTTP server on port 8888
Server is ready.
打開瀏覽器進行訪問:ip+埠(8888)

在最后面有OQL查詢功能,

進入頁面,輸入下面陳述句查詢字串大于10000,點擊Execute按鈕,查詢結果:
select s from java.lang.String s where s.value.length >= 10000

2、通過MAT工具對dump檔案進行分析(官網)
MAT(Memory Analyzer Tool),一個基于Eclipse的記憶體分析工具,是一個快速、功能豐富的JAVA heap分析工具,它可以幫助我們查找記憶體泄漏和減少記憶體消耗,使用記憶體分析工具從眾多的物件中進行分析,快速的計算出在記憶體中物件的占用大小,看看是誰阻止了垃圾收集器的回收作業,并可以通過報表直觀的查看到可能造成這種結果的物件,
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-I9geT1sO-1629355535351)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819114901423.png)]](https://img.uj5u.com/2021/08/21/258649210750576.png)
2.1、下載安裝
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-V7GQluyM-1629355535352)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819134930028.png)]](https://img.uj5u.com/2021/08/21/258649210750577.png)
運行獨立版 Memory Analyzer 所需的最低 Java 版本是 Java 11 如果本地安裝的JDK是更低版本的可以下載舊版本,
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-N61htSA0-1629355535352)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819140452413.png)]](https://img.uj5u.com/2021/08/21/258649210750578.png)
下載完成后解壓MemoryAnalyzer-1.8.1.20180910-win32.win32.x86_64.zip,解壓后如圖
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-OU9rJl0G-1629355535353)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819140912714.png)]](https://img.uj5u.com/2021/08/21/258649210750579.png)
2.2、使用方式



查看物件以及它的依賴:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1WdBhgpu-1629355535355)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819141903120.png)]](https://img.uj5u.com/2021/08/21/258649210750572.png)
查看可能存在記憶體泄露的分析:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HSgNBWKc-1629355535355)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819142008106.png)]](https://img.uj5u.com/2021/08/21/2586492107505713.png)
3、記憶體溢位的定位與分析
引起記憶體溢位的原因有很多種,常見的有以下幾種:
- 記憶體中加載的資料量過于龐大,如一次從資料庫取出過多資料,
- 集合類中有對物件的參考,使用完后未清空,使得JVM不能回收,
- 代碼中存在死回圈或回圈產生過多重復的物件物體,
- 使用的第三方軟體中的BUG,
- 啟動引數記憶體值設定的過小,
記憶體溢位在實際的生產環境中經常會遇到,如,不斷的將資料寫入到一個集合中,出現了死回圈或者讀取超大的檔案等等,都可能會造成記憶體溢位,如果出現了記憶體溢位,首先我們需要定位到發生記憶體溢位的環節,并且進行分析,是正常還是非正常情況,如果是正常的需求,就應該考慮加大記憶體的設定,如果是非正常需求,那么就要對代碼進行修改,修復這個bug,
3.1、模擬記憶體溢位
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class TestJvmOutOfMemory {
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
for (int i = 0; i < 10000000; i++) {
String str = "";
for (int j = 0; j < 1000; j++) {
str += UUID.randomUUID().toString();
}
list.add(str);
}
System.out.println("ok");
}
}
為了更快的現實效果,這里使用Idea,設定執行的引數
#在每次發生記憶體溢位時,JVM會自動將堆轉儲,dump檔案存放在-XX:HeapDumpPath指定的路徑下,
-Xms8m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:

測驗結果如下:

匯入到MAT工具中進行分析
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-N0a7OZ1h-1629355535357)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819144134395.png)]](https://img.uj5u.com/2021/08/21/2586492107505716.png)
可以看到,有87.02%的記憶體由Object[]陣列占有,所以比較可疑,
分析:已經有超過87%的記憶體都被它占有,這種情況是非常有可能出現記憶體溢位的
查看詳情:
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4da6MWYn-1629355535358)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210819144329342.png)]](https://img.uj5u.com/2021/08/21/2586492107505717.png)
可以看到集合中存盤了大量的uuid字串,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/295164.html
標籤:java
上一篇:Java 中的各種鎖
