• 如何找内存泄露


    先写一段这样的程序:
    #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
    这样的效果 
        这样泄露的位置就很清楚的找到了

  • 相关阅读:
    android xml解析添加到listview中的问题
    jquery重写一个对话框
    linq join多字段
    asp.net添加验证码
    基本知识点罗列
    wordpress添加文章浏览统计(刷新不重复)
    vue使用SockJS实现webSocket通信
    el-table的多选框表头增加全选字样
    js如何在一个日期上面加上几小时 几分钟 几秒
    高德地图-Vue-amap实现POI搜索+自定义点
  • 原文地址:https://www.cnblogs.com/kissfu/p/3465787.html
Copyright © 2020-2023  润新知