如何找内存泄露

先写一段这样的程序:
#include "stdafx.h"
#include <windows.h>

void AllocateMemory() 

     int* a = new int[2000]; 
     for(int i=0;i<2000;i++)
  {
  *a=0;
  a++;
  }
     Sleep(1); 
}

int _tmain(int argc, _TCHAR* argv[])
{   while(1) 
     { 
        AllocateMemory(); 
     } 
     return 0; 
}

然后打开windbg,attach上这个程序(非侵入),在DbgBreakPoint停止
输入命令:!heap -s
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
00150000 00000002    1024     16     16      2     1     1    0      0   L  
00250000 00001002      64     24     24     15     1     1    0      0   L  
00260000 00008000      64     12     12     10     1     1    0      0      
00380000 00001002      64     16     16      1     1     1    0      0   L  
003a0000 00001002  130112  73260  73260     33     7     1    0      0   L  
-----------------------------------------------------------------------------

然后让它继续运行,输入g
过一会再将它break.

0:001> !heap -s
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
00150000 00000002    1024     16     16      2     1     1    0      0   L  
00250000 00001002      64     24     24     15     1     1    0      0   L  
00260000 00008000      64     12     12     10     1     1    0      0      
00380000 00001002      64     16     16      1     1     1    0      0   L  
003a0000 00001002  130112  97020  97020     35     7     1    0      0   L  
-----------------------------------------------------------------------------

然后再g,过一会再break.
0:001> !heap -s
  Heap     Flags   Reserv  Commit  Virt   Free  List   UCR  Virt  Lock  Fast 
                    (k)     (k)    (k)     (k) length      blocks cont. heap 
-----------------------------------------------------------------------------
00150000 00000002    1024     16     16      2     1     1    0      0   L  
00250000 00001002      64     24     24     15     1     1    0      0   L  
00260000 00008000      64     12     12     10     1     1    0      0      
00380000 00001002      64     16     16      1     1     1    0      0   L  
003a0000 00001002  261184 179204 179204     35     8     1    0      0   L  
-----------------------------------------------------------------------------

注意看003a0000地址,它申请的内存和使用的内存都一直再长。 说明这个堆地址有泄漏。

对这个堆做个统计:

!heap -stat -h 003a0000 
 heap @ 003a0000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    1f40 597c - aec6300  (99.99)
    800 2 - 1000  (0.00)
    48a 1 - 48a  (0.00)
    214 2 - 428  (0.00)
    245 1 - 245  (0.00)
    220 1 - 220  (0.00)
    94 2 - 128  (0.00)
    72 2 - e4  (0.00)
    c8 1 - c8  (0.00)
    54 2 - a8  (0.00)
    90 1 - 90  (0.00)
    48 2 - 90  (0.00)
    8e 1 - 8e  (0.00)
    88 1 - 88  (0.00)
    44 2 - 88  (0.00)
    80 1 - 80  (0.00)
    2a 3 - 7e  (0.00)
    76 1 - 76  (0.00)
    39 2 - 72  (0.00)
    26 3 - 72  (0.00)
发现这个堆中,大小为1f40的内存块最多。
根据大小过滤下这个
!heap -flt s 1f40
    _HEAP @ 150000
    _HEAP @ 250000
    _HEAP @ 260000
    _HEAP @ 380000
    _HEAP @ 3a0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        003a5c70 03e9 0000  [01]   003a5c78    01f40 - (busy)
        003a7bb8 03e9 03e9  [01]   003a7bc0    01f40 - (busy)
        003a9b00 03e9 03e9  [01]   003a9b08    01f40 - (busy)
        003aba48 03e9 03e9  [01]   003aba50    01f40 - (busy)
        003ad990 03e9 03e9  [01]   003ad998    01f40 - (busy)
        00410040 03e9 03e9  [01]   00410048    01f40 - (busy)
        00411f88 03e9 03e9  [01]   00411f90    01f40 - (busy)
        00413ed0 03e9 03e9  [01]   00413ed8    01f40 - (busy)
        00415e18 03e9 03e9  [01]   00415e20    01f40 - (busy)
        00417d60 03e9 03e9  [01]   00417d68    01f40 - (busy)
        00419ca8 03e9 03e9  [01]   00419cb0    01f40 - (busy)
        0041bbf0 03e9 03e9  [01]   0041bbf8    01f40 - (busy)
        0041db38 03e9 03e9  [01]   0041db40    01f40 - (busy)
        0041fa80 03e9 03e9  [01]   0041fa88    01f40 - (busy)
        004219c8 03e9 03e9  [01]   004219d0    01f40 - (busy)
        00423910 03e9 03e9  [01]   00423918    01f40 - (busy)
        00425858 03e9 03e9  [01]   00425860    01f40 - (busy)
        004277a0 03e9 03e9  [01]   004277a8    01f40 - (busy)
        004296e8 03e9 03e9  [01]   004296f0    01f40 - (busy)
        0042b630 03e9 03e9  [01]   0042b638    01f40 - (busy)
        ... ...

明显可以看到3a0000中有不少这种内存块。取一个UserPtr,调用!heap -p -a UsrPtr

这样可以显示出这个块的调用栈。
0:001> !heap -p -a 0b2fe198
    address 0b2fe198 found in
    _HEAP @ 3a0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0b2fe190 03e9 0000  [01]   0b2fe198    01f40 - (busy)

这里什么都没有,当然你需要配置操作系统标志来启动跟踪内存泄露进程的user stack。
启动方法就是运行下面指令gflags.exe /i Testleak.exe +ust。

这样运行上面命令就有
!heap -p -a 0143d8c8 
    address 0143d8c8 found in
    _HEAP @ 330000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0143d8c0 03f0 0000  [07]   0143d8c8    01f64 - (busy)
        Trace: 0025
        7c96d6dc ntdll!RtlDebugAllocateHeap+0x000000e1
        7c949d18 ntdll!RtlAllocateHeapSlowly+0x00000044
        7c91b298 ntdll!RtlAllocateHeap+0x00000e64
        102c103e MSVCR90D!_heap_alloc_base+0x0000005e
        102cfd76 MSVCR90D!_heap_alloc_dbg_impl+0x000001f6
        102cfb2f MSVCR90D!_nh_malloc_dbg_impl+0x0000001f
        102cfadc MSVCR90D!_nh_malloc_dbg+0x0000002c
        102db25b MSVCR90D!malloc+0x0000001b
        102bd691 MSVCR90D!operator new+0x00000011
        102bd71f MSVCR90D!operator new[]+0x0000000f
        4113d8 Test2!AllocateMemory+0x00000028
        41145c Test2!wmain+0x0000002c
        411a08 Test2!__tmainCRTStartup+0x000001a8
        41184f Test2!wmainCRTStartup+0x0000000f
        7c816fd7 kernel32!BaseProcessStart+0x00000023
这样的效果 
    这样泄露的位置就很清楚的找到了

posted @ 2013-12-09 17:27  亲福  阅读(397)  评论(0编辑  收藏  举报