jvm学习之-jmap

一. 简单说明

jmap是和JVM堆内存相关的命令,比如dump出堆内存、堆内存的基本使用情况、堆内存使用情况直方图等等。

二. 使用方法

1
jmap <option> pid
选项 说明 影响程度 重要程度
-heap 显示堆内存的详细信息(例如:回收器信息、分代内存等等) 不会对线上有影响 五星
-histo 显示堆内存中对象的统计信息,类似直方图 不会对线上有影响 五星
-dump 生成堆内存的快照 轻易不要在线上使用 四星
-F 强制生成快照 轻易不要在线上使用  四星
-permstat 以classloader为统计口径查看永久代信息 测试了一下应该对线上有影响(确实没用过) 三星
1
下面以pid=18247为例子

1. -heap

##### (1) 查看jvm的相关参数

1
java -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -server -Xmx1g -Xms1g -Xmn256m -XX:PermSize=128m -XX:MaxPermSize=128m -Xss256k -XX:SurvivorRatio=10 -XX:MaxDirectMemorySize=512m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -verbose:gc -Xloggc:../logs/gc.log -XX:HeapDumpPath=../logs/java.hprof -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:-OmitStackTraceInFastThrow -XX:+PrintCommandLineFlags

(2) 执行并分析jmap -heap
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
$ jmap -heap 18247
Attaching to process ID 18247, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.51-b03
using parallel threads in the new generation.
using thread-local object allocation.
#老年代使用的CMS
Concurrent Mark-Sweep GC
#堆的基本配置
Heap Configuration:
MinHeapFreeRatio = 40 #默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
MaxHeapFreeRatio = 70 #默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
MaxHeapSize = 1073741824 (1024.0MB) # -Xmx1g
NewSize = 268435456 (256.0MB) # -Xmn256m (1.3 1.4的参数,可能这里兼容Xmn)
MaxNewSize = 268435456 (256.0MB) # -Xmn256m (1.3 1.4的参数,可能这里兼容Xmn)
OldSize = 5439488 (5.1875MB) # -XX:oldSize (应该是比较老的参数了,应该是作废了)
NewRatio = 2 # -XX:NewRatio,新生代和老生代的大小比值(Xms=Xmx并且设置Xmn时,这个参数无效)
SurvivorRatio = 10 # -XX:SuvivorRatio,年轻代中Eden区与suivivor区的大小比值(那两个survivor与一个eden区的比值是2:10)
PermSize = 134217728 (128.0MB) # -XX:PermSize=128m
MaxPermSize = 134217728 (128.0MB) # -XX:MaxPermSize=128m
G1HeapRegionSize = 0 (0.0MB) # 没有使用G1垃圾回收器
#堆的使用情况
Heap Usage:
#真正在使用的是一个eden和一个survivor,有一个survior是空闲的
#256 * 11 / (10 + 1 + 1) = 234.6M
New Generation (Eden + 1 Survivor Space):
capacity = 246087680 (234.6875MB)
used = 24672032 (23.529083251953125MB)
free = 221415648 (211.15841674804688MB)
10.025707910286284% used
#256 * 10 / (10 + 1 + 1 )= 213.3M
Eden Space:
capacity = 223739904 (213.375MB)
used = 21503216 (20.507064819335938MB)
free = 202236688 (192.86793518066406MB)
9.610809522828793% used
# 256 * 1 / (10 + 1 + 1 )= 21.3M
From Space:
capacity = 22347776 (21.3125MB)
used = 3168816 (3.0220184326171875MB)
free = 19178960 (18.290481567382812MB)
14.179558628115835% used
# 256 * 1 / (10 + 1 + 1 )= 21.3M
To Space:
capacity = 22347776 (21.3125MB)
used = 0 (0.0MB)
free = 22347776 (21.3125MB)
0.0% used
#老年代(用的CMS)
#1024 -256 = 768M
concurrent mark-sweep generation:
capacity = 805306368 (768.0MB)
used = 304923168 (290.7973937988281MB)
free = 500383200 (477.2026062011719MB)
37.86424398422241% used
Perm Generation:
capacity = 134217728 (128.0MB)
used = 48306552 (46.06871795654297MB)
free = 85911176 (81.93128204345703MB)
35.991185903549194% used
23134 interned Strings occupying 2077032 bytes.
(3) 一些重要信息
  • SurvivorRatio=x代表两个survivor和eden的比率是2:x。
  • Heap Usage中的New Generation = 一个eden + 一个survior,原因是因为在年轻代使用了复制算法。
  • Heap Configuration中的很多参数都作废了,不要特别进行关注,否则容易混淆。

2. -histo

histo可以计算出className, 对象个数,所占内存的一个统计表。(以所占内存倒序)。
通常来说,我们比较关心钱多少个,对于分析内存溢出和泄露比较有帮助(尤其是自己公司的包名)。
所以通常我们可以只关心前10~50最大的,就可以执行这个命令。
这种方式可以不需要dump出堆内存,使用MAT那样的工具来分析,就可以得到堆的统计信息,在实际生产中是一个很有帮助的命令。

1
2
3
4
5
6
7
8
9
10
11
# jmap -histo 18247 | head -10
num #instances #bytes class name
----------------------------------------------
1: 2682133 85828256 org.wltea.analyzer.dic.DictSegment
2: 243743 67284136 [B
3: 1454260 46536320 [Lorg.wltea.analyzer.dic.DictSegment;
4: 1368664 43797248 java.util.HashMap$Entry
5: 538351 35473920 [C
6: 527286 12654864 java.lang.String
7: 80443 12367216 [Ljava.util.HashMap$Entry;

3. -dump

把整个堆内存dump到硬盘中,后期可以结合MAT来进行详细分析。
-dump[live,] live代表只把活的对象dump出来。

1
2
3
$ jmap -dump:format=b,file=dump.bin 18247
Dumping heap to /root/dump.bin ...
Heap dump file created

除了这个方法还有几种方法能将堆内存dump出来:
1.-XX:+HeadDumpOnOutOfMemoryError:在出现OOM异常自动dump
2.-XX:+HeapDumpOnCtrlBreak: ctrl + break键,这个不太常用
3.kill -3: 这个也不常用。

三、简单总结

jmap还是一个分析堆内存使用情况比较实用的一个工具(heap histo dump),如果想更为详细的分析堆内存的使用,可以使用MAT进行,以后有机会再进行介绍。

四、参考文档

JVM系列三:JVM参数设置、分析