1. 程式人生 > 實用技巧 >jmap命令 檢查記憶體洩漏

jmap命令 檢查記憶體洩漏

命令介紹

jmap - Prints shared object memory maps or heap memory details for a process, core file, or remote
debug server.

jmap不僅能生成dump檔案,還闊以查詢finalize執行佇列、Java堆和永久代的詳細資訊,如當前使用率、當前使用的是哪種收集器等。主要的作用是檢查記憶體洩漏、物件建立不合理和銷燬等問題

語法: 

jmap [ options ] pid

jmap [ options ] executable core

jmap [ options ] [ pid ] server-id@ ] remote-hostname-or-IP

常用選項

-dump:[live,] format=b, file=filename

dump堆使用資訊到檔案,format指定格式,live指存活的物件,file為檔名

[root@node1 ~]# jmap -dump:live,format=b,file=hprof.dump 2712
2712: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding

報錯原因:

jvm執行時會生成一個目錄hsperfdata_$USER($USER是啟動java程序的使用者),在linux中預設是/tmp。目錄下會有些pid檔案,存放jvm程序資訊。
jvm相關命令會從這個路徑/tmp/hsperfdata_$USER去獲取pid的連線資訊,我是root使用者執行的命令,所以沒有pid檔案,而對應應用程式裡面有

例如:

jmap報錯原因:

可能是由於tmpwatch機制,防止/tmp目錄裡檔案過多,系統每天基於此機制刪除超過240小時未訪問的檔案和目錄。

 jmap和jstack不能正常執行的原因:

因為對應目錄裡沒有pid檔案

  檢視關鍵配置/etc/cron.daily/tmpwatch:

  flags=-umc /usr/sbin/tmpwatch "$flags" 
  -x /tmp/.X11-unix -x /tmp/.XIM-unix \ 
  -x /tmp/.font-unix -x /tmp/.ICE-unix 
  -x /tmp/.Test-unix 240 /tmp /usr/sbin/tmpwatch "$flags" 720 /var/tmp 
  for d in /var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}; 
  do if [ -d "$d" ]; then /usr/sbin/tmpwatch "$flags" -f 720 "$d" fi done

解決辦法:

1、修改對應應用的Djava.io.tmpdir引數,統一使用/tmp目錄。重啟應用

2、修改/etc/cron.daily/tmpwatch

/usr/sbin/tmpwatch "$flags" -x /tmp/hsperfdata_* -x /tmp/.X11-unix -x /tmp/.XIM-unix
-x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix 240 /tmp

[root@node1 ~]# jmap -F -dump:live,format=b,file=hprof.dump 2712
Attaching to process ID 2712, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.201-b09
Dumping heap to hprof.dump ...
Heap dump file created

dump.hprof這個字尾是為了後續可以直接用MAT(Memory Anlysis Tool)開啟。

-finalizerinfo :列印等待回收物件的資訊

[root@node1 ~]# jmap -finalizerinfo 2712
Attaching to process ID 2712, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.201-b09
Number of objects pending for finalization: 0

可以看到當前F-QUEUE佇列中並沒有等待Finalizer執行緒執行finalizer方法的物件。

-heap :列印heap的概要資訊,GC使用的演算法,heap的配置及wise heap的使用情況,可以用此來判斷記憶體目前的使用情況以及垃圾回收情況

[root@node1 ~]# jmap -heap 2712
Attaching to process ID 2712, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.201-b09

using thread-local object allocation.
Parallel GC with 2 thread(s)   # GC方式

Heap Configuration:   // 堆記憶體初始化配置


MinHeapFreeRatio = 0    // 對應jvm啟動引數-XX:MinHeapFreeRatio設定JVM堆最小空閒比率(default 40)


MaxHeapFreeRatio = 100  // 對應jvm啟動引數 -XX:MaxHeapFreeRatio設定JVM堆最大空閒比率(default 70)


MaxHeapSize = 52428800 (50.0MB)  // 對應jvm啟動引數-XX:MaxHeapSize=設定JVM堆的最大大小


NewSize = 17301504 (16.5MB)  // 對應jvm啟動引數-XX:NewSize=設定JVM堆的‘新生代’的預設大小


MaxNewSize = 17301504 (16.5MB) // 對應jvm啟動引數-XX:MaxNewSize=設定JVM堆的‘新生代’的最大大小


OldSize = 35127296 (33.5MB) // 對應jvm啟動引數-XX:OldSize=<value>:設定JVM堆的‘老生代’的大小


NewRatio = 2  // 對應jvm啟動引數-XX:NewRatio=:‘新生代’和‘老生代’的大小比率


SurvivorRatio = 8  // 對應jvm啟動引數-XX:SurvivorRatio=設定年輕代中Eden區與Survivor區的大小比值 


MetaspaceSize = 21807104 (20.796875MB) // 對應jvm啟動引數-XX:PermSize=<value>:設定JVM堆的‘永生代’的初始大小


CompressedClassSpaceSize = 1073741824 (1024.0MB)  // 對應jvm啟動引數-XX:MaxPermSize=<value>:設定JVM堆的‘永生代’的最大大小


MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)

Heap Usage:  // 堆記憶體使用情況


PS Young Generation
Eden Space: // Eden區記憶體分佈


capacity = 9961472 (9.5MB)  // Eden區總容量


used = 3917840 (3.7363433837890625MB) // Eden區已使用


free = 6043632 (5.7636566162109375MB) // Eden區剩餘容量


39.32993035567434% used  // Eden區使用比率


From Space: // 其中一個Survivor區的記憶體分佈


capacity = 3670016 (3.5MB)
used = 1028528 (0.9808807373046875MB)
free = 2641488 (2.5191192626953125MB)
28.025163922991073% used
To Space:  // 另一個Survivor區的記憶體分佈


capacity = 3145728 (3.0MB)
used = 0 (0.0MB)
free = 3145728 (3.0MB)
0.0% used
PS Old Generation // 當前的Old區記憶體分佈


capacity = 35127296 (33.5MB)
used = 27684384 (26.401885986328125MB)
free = 7442912 (7.098114013671875MB)
78.81159995918843% used

20704 interned Strings occupying 2153624 bytes.

-histo :列印堆的物件統計,包括物件數、記憶體大小等等 (因為在dump:live前會進行full gc,如果帶上live則只統計活物件,因此不加live的堆大小要大於加live堆的大小 )

[root@node1 ~]# jmap -F -histo 2656

num #instances #bytes Class description
--------------------------------------------------------------------------
1:    526458    45456832    char[]
2:    275076    6601824    java.lang.String
3:    44613    5271264    byte[]
4:    215455    5170920    java.util.concurrent.ConcurrentSkipListMap$Node
5:    62357    4515576    int[]
6:    109775    2634600    java.lang.Double
7:    74848    2395136    java.util.HashMap$Node
8:    18442    1880400    java.util.HashMap$Node[]
9:    53471    1820904    java.lang.Object[]


  ....
僅僅列印了前10行

xml class name是物件型別,說明如下:

B  byte
C  char
D  double
F  float
I  int
J  long
Z  boolean
[  陣列,如[I表示int[]
[L+類名 其他物件

-F :強制模式。如果指定的pid沒有響應,請使用jmap -dump或jmap -histo選項。此模式下,不支援live子選項

另外,jmap命令生成的hprof檔案可以使用jhat進行分析