pmap學習:系統測試中怎麼確定內存泄露(memory leak)

性能測試的一項重要工作就是檢查有沒有內存泄露。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或者在系統穩定後還在持續增長,那就需要分析了。在我的工作中,一般前面半個小時的內存增長我都忽略。

D) 我們會發現,VSZ或者其他增長以後即使你調用了free/delete也不一定會減少或者回復到初始水平。這是系統的正常行爲,釋放的那一部份空間馬上就能重用。

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 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


 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章