https://www.jianshu.com/p/871d6bb3a32d复制
在服务器性能优化内存这一项时,有一些现象很诡异。如top显示的RES很大,但是实际jvm堆内存占用很小,同时使用nmt发现committed更大。所以决定写这篇wiki大概介绍一下
top(res)
$ top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14730 landon 20 0 9283m 1.6g 19m S 0.3 20.5 30:43.57 java
复制
jstat
$ jstat -gc 14730
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
143360.0 143360.0 0.0 0.0 1146880.0 27569.6 4300800.0 88770.2 40448.0 39299.8 4648.0 4382.2 18 1.441 4 1.213 2.654
$ jstat -gcutil 14730
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 2.40 2.06 97.16 94.28 18 1.441 4 1.213 2.654
复制
jmap
$ jmap -heap 14730
Attaching to process ID 14730, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.172-b11
using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 5872025600 (5600.0MB)
NewSize = 1468006400 (1400.0MB)
MaxNewSize = 1468006400 (1400.0MB)
OldSize = 4404019200 (4200.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 = 1321205760 (1260.0MB)
used = 44450000 (42.39082336425781MB)
free = 1276755760 (1217.6091766357422MB)
3.364351060655382% used
Eden Space:
capacity = 1174405120 (1120.0MB)
used = 44450000 (42.39082336425781MB)
free = 1129955120 (1077.6091766357422MB)
3.7848949432373047% used
From Space:
capacity = 146800640 (140.0MB)
used = 0 (0.0MB)
free = 146800640 (140.0MB)
0.0% used
To Space:
capacity = 146800640 (140.0MB)
used = 0 (0.0MB)
free = 146800640 (140.0MB)
0.0% used
concurrent mark-sweep generation:
capacity = 4404019200 (4200.0MB)
used = 90900656 (86.68962097167969MB)
free = 4313118544 (4113.31037902832MB)
2.0640385945638022% used
14494 interned Strings occupying 1262456 bytes.
$ jmap -histo:live 14730 | head -13
num #instances #bytes class name
----------------------------------------------
1: 341052 13981272 [C
2: 194673 11402072 [Ljava.lang.Object;
3: 337876 8109024 java.lang.String
4: 227540 7281280 java.util.HashMap$Node
5: 180237 7209480 landon.WordFilterService$WordNode
6: 62226 5685448 [Ljava.util.HashMap$Node;
7: 220913 5301912 java.util.ArrayList
8: 17448 4789712 [B
9: 3841 4219752 [I
10: 62187 2984976 java.util.HashMap
$ jmap -dump:format=b,live,file=RobotMemoryLeak3.hprof 995
复制
nmt工具
$ jcmd 14730 VM.native_memory summary
14730:
Native Memory Tracking:
Total: reserved=7316712KB, committed=6043896KB
- Java Heap (reserved=5734400KB, committed=5734400KB)
(mmap: reserved=5734400KB, committed=5734400KB)
- Class (reserved=1086288KB, committed=41296KB)
(classes #6377)
(malloc=848KB #10714)
(mmap: reserved=1085440KB, committed=40448KB)
- Thread (reserved=91890KB, committed=91890KB)
(thread #90)
(stack: reserved=91492KB, committed=91492KB)
(malloc=292KB #452)
(arena=105KB #176)
- Code (reserved=253971KB, committed=26147KB)
(malloc=4371KB #6376)
(mmap: reserved=249600KB, committed=21776KB)
- GC (reserved=32269KB, committed=32269KB)
(malloc=12661KB #180)
(mmap: reserved=19608KB, committed=19608KB)
- Compiler (reserved=429KB, committed=429KB)
(malloc=298KB #509)
(arena=131KB #6)
- Internal (reserved=4983KB, committed=4983KB)
(malloc=4951KB #9495)
(mmap: reserved=32KB, committed=32KB)
- Symbol (reserved=9467KB, committed=9467KB)
(malloc=7605KB #71844)
(arena=1862KB #1)
- Native Memory Tracking (reserved=1801KB, committed=1801KB)
(malloc=197KB #2791)
(tracking overhead=1603KB)
- Arena Chunk (reserved=190KB, committed=190KB)
(malloc=190KB)
- Unknown (reserved=101024KB, committed=101024KB)
(mmap: reserved=101024KB, committed=101024KB)
Virtual memory map:
$ jcmd 14730 VM.native_memory detail | less
......
[0x0000000662000000 - 0x00000007c0000000] reserved 5734400KB for Java Heap from
[0x00007f755bf42482] ReservedSpace::initialize(unsigned long, unsigned long, bool, char*, unsigned long, bool)+0xc2
[0x00007f755bf42e5e] ReservedHeapSpace::ReservedHeapSpace(unsigned long, unsigned long, bool, char*)+0x6e
[0x00007f755bf0fe9b] Universe::reserve_heap(unsigned long, unsigned long)+0x8b
[0x00007f755ba63ad2] GenCollectedHeap::allocate(unsigned long, unsigned long*, int*, ReservedSpace*)+0x182
[0x00000006b9800000 - 0x00000007c0000000] committed 4300800KB from
[0x00007f755bf41ef9] VirtualSpace::expand_by(unsigned long, bool)+0x199
[0x00007f755bf42a4e] VirtualSpace::initialize(ReservedSpace, unsigned long)+0xee
[0x00007f755ba74a01] CardGeneration::CardGeneration(ReservedSpace, unsigned long, int, GenRemSet*)+0xf1
[0x00007f755b95f9de] ConcurrentMarkSweepGeneration::ConcurrentMarkSweepGeneration(ReservedSpace, unsigned long, int, CardTableRS*, bool, FreeBlockDictionary<FreeChunk>::DictionaryChoice)+0x4e
[0x0000000662000000 - 0x00000006b9800000] committed 1433600KB from
[0x00007f755bf41ef9] VirtualSpace::expand_by(unsigned long, bool)+0x199
[0x00007f755bf42a4e] VirtualSpace::initialize(ReservedSpace, unsigned long)+0xee
[0x00007f755ba744ad] Generation::Generation(ReservedSpace, unsigned long, int)+0xbd
[0x00007f755b97afa6] DefNewGeneration::DefNewGeneration(ReservedSpace, unsigned long, int, char const*)+0x46
...
复制
pmap
$ pmap -x 14730
14730: /bin/java -server -XX:NativeMemoryTracking=detail -cp lib/mavs-0.0.1-SNAPSHOT.jar -Djava.ext.dirs=lib:/lib/ext -XX:+HeapDumpOnOutOfMemoryError -XX:NewSize=1400m -XX:MaxNewSize=1400m -Xms5600m -Xmx5600m -XX:+UseConcMarkSweepGC -Dlog.home=/log/backend -Dlogback.configurationFile=config/logback.xml
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 4 4 0 r-x-- java
0000000000600000 4 4 4 rw--- java
0000000002599000 132 36 36 rw--- [ anon ]
0000000662000000 5739048 1416320 1416320 rw--- [ anon ]
......
复制
google-perftools#分析堆外内存
-Xms100m -Xmx1000m
, the JVM will reserve 1000 MB for the Java Heap. Since the initial heap size is only 100 MB, only 100MB will be committed to begin withtop显示的res是指进程常驻内存 目前从经验上看这个常驻内存会比堆内存大 这个很容易理解 因为jvm除了堆内存外,还有metaspace、stack、jvm本身、堆外内存等
使用nmt工具可以看到committed size比较大 比rss要大 这其实也可以理解 rss其实是真用使用的物理内存 而committed只是提交内存 而这些提交内存可能还没真正被touch
通常我们主要关注java堆内存,可以使用jmap来追踪内存使用和内存实例对象占用等 如果要追踪大对象 则可以使用jmap dump出堆快照后用mat等工具分析
如果发现res占用非常大 那么要怀疑可能是堆外内存泄露
free这个命令可能有时候比较另外迷惑
$ free -h
total used free shared buffers cached
Mem: 7.8G 5.8G 2.0G 940K 220M 3.7G
-/+ buffers/cache: 1.9G 5.9G
Swap: 0B 0B 0B
复制