转自:https://blog.csdn.net/licanhua/article/details/6983534
性能测试的一项重要工作就是检查有没有内存泄露。linux下通过top/free/pmap/ps,会提供许多关于内存分配的信息,如top里面的VIRT,RSS,SWAP,VSZ,RES,SHR等等,到底哪些参数能够用来检测memory leak呢?虽然baidu,google很方便,但是一直没有找到一个令人信服的答案。这些天一直在研究,结合我在以往实际工作中的一些经验,在此做一个总结:
1,首先使用sar/top/free在系统级确定是否有内存泄露。如有,可以从top输出确定哪一个process。
2,pmap/top/ps工具是能帮助确定process是否有memory leak。确定memory leak的原则:
A)VIRT/VSZ或者writeable/private (‘pmap –d’输出)如果在做重复的操作过程中一直保持稳定增长,那么一定有内存泄露。
B) RSS只能作为参考,不能用来确定是否有内存泄露。
C) 在performance testing过程中,前面一段时间的内存增长不能用来确定内存泄露。因为最初系统需要申请一些内存来处理traffic。如果内存在短期就增长数G或者在系统稳定后还在持续增长,那就需要分析了。在我的工作中,一般前面半个小时的内存增长我都忽略。
E)多次申请分配的地址空间可能不连续。在virtual address中有多个[anon]段。 Here 1M was alloated to000000001b56a000 and00002ac25a77c000.
000000001b56a000 1156 12 12 rw--- [ anon ]
00002ac25a77c000 1040 16 16 rw--- [ anon ]
以下的测试可以证明以上的推论。
示例代码:
程序输出:
XX48-0-0-1:/root-# ./a.out
global_i_init: 0x500cc0
global_k non_init : 0x500cc4
static_global_j : 0x500cb8
stack i : 0x7fff0120ab5c
data allocate 100k @0x1b56a010
data allocate 1M i@0x2ac25a77f010
data write at x2[1024*1024-1]
data read at x2
delete x2
delete x
data allocate 1M i@0x1b56a010
pmap -d 输出:
mapped | writeable/private: | shared | ||
STEP 1 | init | 19616K | 236K | 0 |
STEP 2 | new 100k | 19848K | 468K | 0 |
STEP 3 | new 1M | 20876K | 1496K | 0 |
STEP 4 | write 1 byte | 20876K | 1496K | 0 |
STEP 5 | read 1M | 20876K | 1496K | 0 |
STEP 6 | delete 1M | 19848K | 468K | 0 |
STEP 7 | delete 100k | 19848K | 468K | 0 |
STEP 8 | new 1M | 20772K | 1392K | 0 |
pmap -d 结论:
1, mapped 和writeable/private 能够反映内存的变化.
2, delete 和free 不能在 mapped 和writeable/private 立即反映出来,比方删除100k就没有变化.
pmap -x output:
Total kbytes | RSS | Dirty | ||
STEP 1 | init | 19616 | 912 | 124 |
STEP 2 | new 100k | 19848 | 976 | 140 |
STEP 3 | new 1M | 20876 | 980 | 144 |
STEP 4 | write 1 byte | 20876 | 984 | 148 |
STEP 5 | read 1M | 20876 | 2004 | 148 |
STEP 6 | delete 1M | 19848 | 976 | 140 |
STEP 7 | delete 100k | 19848 | 980 | 140 |
STEP 8 | new 1M | 20772 | 984 | 144 |
Address | kbytes | RSS | Dirty | ||
STEP 1 | init | ||||
STEP 2 | new 100k | 000000001b56a000 | 232 | 8 | 8 |
STEP 3 | new 1M | 000000001b56a000 | 232 | 8 | 8 |
STEP 4 | write 1 byte | 000000001b56a000 | 232 | 8 | 8 |
STEP 5 | read 1M | 000000001b56a000 | 232 | 8 | 8 |
STEP 6 | delete 1M | 000000001b56a000 | 232 | 8 | 8 |
STEP 7 | delete 100k | 000000001b56a000 | 232 | 8 | 8 |
STEP 8 | new 1M | 000000001b56a000 | 1156 | 12 | 12 |
Address | kbytes | RSS | Dirty | ||
STEP 1 | init | 00002ac25a77c000 | 12 | 12 | 12 |
STEP 2 | new 100k | 00002ac25a77c000 | 12 | 12 | 12 |
STEP 3 | new 1M | 00002ac25a77c000 | 1040 | 16 | 16 |
STEP 4 | write 1 byte | 00002ac25a77c000 | 1040 | 20 | 20 |
STEP 5 | read 1M | 00002ac25a77c000 | 1040 | 1040 | 20 |
STEP 6 | delete 1M | 00002ac25a77c000 | 12 | 12 | 12 |
STEP 7 | delete 100k | 00002ac25a77c000 | 12 | 12 | 12 |
STEP 8 | new 1M | 00002ac25a77c000 | 12 | 12 | 12 |
pmap -x 结论:
1, 尽管你已经调用了 new分配内存(step 3), 但是 OS不一定一下把所有的page都分配。本例中只有对那一块已经分配内存进行读 (STEP5)或者写(STEP4) 的时候才提交实际内存。
pmap -x:
2, 多次相同的new操作可能在不同的[anon]虚拟地址空间分配。本例中第一个1M分配在00002ac25a77c000, 而第二个1M跑到000000001b56a000。中间跨度很大。
最终pmap -d:
Address Kbytes Mode Offset Device Mapping
0000000000400000 4 r-x-- 0000000000000000 008:00001 a.out
0000000000500000 4 rw--- 0000000000000000 008:00001 a.out
000000001b56a000 1156 rw--- 000000001b56a000 000:00000 [ anon ]
0000003677000000 112 r-x-- 0000000000000000 008:00001 ld-2.5.so
000000367721c000 4 r---- 000000000001c000 008:00001 ld-2.5.so
000000367721d000 4 rw--- 000000000001d000 008:00001 ld-2.5.so
0000003677400000 1336 r-x-- 0000000000000000 008:00001 libc-2.5.so
000000367754e000 2048 ----- 000000000014e000 008:00001 libc-2.5.so
000000367774e000 16 r---- 000000000014e000 008:00001 libc-2.5.so
0000003677752000 4 rw--- 0000000000152000 008:00001 libc-2.5.so
0000003677753000 20 rw--- 0000003677753000 000:00000 [ anon ]
0000003677c00000 520 r-x-- 0000000000000000 008:00001 libm-2.5.so
0000003677c82000 2044 ----- 0000000000082000 008:00001 libm-2.5.so
0000003677e81000 4 r---- 0000000000081000 008:00001 libm-2.5.so
0000003677e82000 4 rw--- 0000000000082000 008:00001 libm-2.5.so
0000003678c00000 52 r-x-- 0000000000000000 008:00001 libgcc_s-4.1.2-20080825.so.1
0000003678c0d000 2048 ----- 000000000000d000 008:00001 libgcc_s-4.1.2-20080825.so.1
0000003678e0d000 4 rw--- 000000000000d000 008:00001 libgcc_s-4.1.2-20080825.so.1
0000003679400000 920 r-x-- 0000000000000000 008:00001 libstdc++.so.6.0.8
00000036794e6000 2044 ----- 00000000000e6000 008:00001 libstdc++.so.6.0.8
00000036796e5000 24 r---- 00000000000e5000 008:00001 libstdc++.so.6.0.8
00000036796eb000 12 rw--- 00000000000eb000 008:00001 libstdc++.so.6.0.8
00000036796ee000 72 rw--- 00000036796ee000 000:00000 [ anon ]
00002ac25a76f000 16 rw--- 00002ac25a76f000 000:00000 [ anon ]
00002ac25a77c000 12 rw--- 00002ac25a77c000 000:00000 [ anon ]
00007fff011f8000 84 rw--- 00007ffffffe9000 000:00000 [ stack ]
00007fff013c2000 12 r-x-- 00007fff013c2000 000:00000 [ anon ]
ffffffffff600000 8192 ----- 0000000000000000 000:00000 [ anon ]
mapped: 20772K writeable/private: 1392K shared: 0K
pmap -x
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 4 4 0 r-x-- a.out
0000000000500000 4 4 4 rw--- a.out
000000001b56a000 1156 12 12 rw--- [ anon ]
0000003677000000 112 96 0 r-x-- ld-2.5.so
000000367721c000 4 4 4 r---- ld-2.5.so
000000367721d000 4 4 4 rw--- ld-2.5.so
0000003677400000 1336 284 0 r-x-- libc-2.5.so
000000367754e000 2048 0 0 ----- libc-2.5.so
000000367774e000 16 16 8 r---- libc-2.5.so
0000003677752000 4 4 4 rw--- libc-2.5.so
0000003677753000 20 16 16 rw--- [ anon ]
0000003677c00000 520 20 0 r-x-- libm-2.5.so
0000003677c82000 2044 0 0 ----- libm-2.5.so
0000003677e81000 4 4 4 r---- libm-2.5.so
0000003677e82000 4 4 4 rw--- libm-2.5.so
0000003678c00000 52 16 0 r-x-- libgcc_s-4.1.2-20080825.so.1
0000003678c0d000 2048 0 0 ----- libgcc_s-4.1.2-20080825.so.1
0000003678e0d000 4 4 4 rw--- libgcc_s-4.1.2-20080825.so.1
0000003679400000 920 404 0 r-x-- libstdc++.so.6.0.8
00000036794e6000 2044 0 0 ----- libstdc++.so.6.0.8
00000036796e5000 24 24 20 r---- libstdc++.so.6.0.8
00000036796eb000 12 12 12 rw--- libstdc++.so.6.0.8
00000036796ee000 72 8 8 rw--- [ anon ]
00002ac25a76f000 16 16 16 rw--- [ anon ]
00002ac25a77c000 12 12 12 rw--- [ anon ]
00007fff011f8000 84 12 12 rw--- [ stack ]
00007fff013c2000 12 4 0 r-x-- [ anon ]
ffffffffff600000 8192 0 0 ----- [ anon ]
---------------- ------ ------ ------
total kB 20772 984 144