性能测试的一项重要工作就是检查有没有内存泄露。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 ]
以下的测试可以证明以上的推论。
示例代码:
#include "stdio.h"
int global_i_init=0;
static int static_global_j=11;
int global_k;
int main () {
int tmp;
printf ("global_i_init: 0x%lx\n",&global_i_init );
printf ("global_k non_init : 0x%lx\n",&global_k );
printf ("static_global_j : 0x%lx\n",&static_global_j );
printf ("stack i : 0x%lx\n",&tmp );
getchar (); // step2
char *x= new char[100*1024];
printf ("data allocate 100k @0x%lx\n", x);
getchar(); // step3
char *x2= new char[1024*1024];
printf ("data allocate 1M i@0x%lx\n", x2);
getchar(); // step4
printf ("data write at x2[1024*1024-1] ");
x2[1024*1024-1]=0;
getchar(); // step5
printf ("data read at x2 ");
int j;
for (int i=0;i<1024*1024; i++)
j=x2[i];
getchar (); // step6
printf ("delete x2");
delete x2;
getchar (); //step 7
printf ("delete x");
delete x;
getchar(); //step8
x2= new char[1024*1024];
printf ("data allocate 1M i@0x%lx\n", x2);
getchar ();
}
程序输出:
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 |