用GFlags和UMDH发现堆内存泄漏

5 篇文章 0 订阅

C++内存泄漏问题

简单来说,就是new/malloc后的内存,没有做delete/free。
这样的问题,难以发现,难以调试。在Windows上,有两个工具,GFlags和UMDH,可以用来发现内存泄漏问题。
我们先写一个C++内存泄漏的程序,然后详细讲解如何用GFlags和UMDH发现内存泄漏问题。

int *getmem(void)
{
    int *p = (int *)malloc(32);
    return p;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int i;
    scanf("%i", &i);//wait for mem leak
    int *x = getmem();//mem leak here
    scanf("%i", &i);//wait to exit
    return 0;
}

很明显,这里malloc的内存,没有释放。用VS2010将程序编译为Win32控制台程序:mem_leak.exe。

程序中之所以设置两个scanf,是为了让程序停下来:

  • 启动程序时,不存在内存泄漏,此时可以dump堆信息1
  • 输入任意数字,触发内存泄漏,程序还能停在这里,便于dump堆信息2

UMDH的原理,就是对堆信息1和堆信息2做diff,通过diff中的allocate与deallocate次数匹配,就能发现内存泄漏问题

GFlags和UMDH具体使用步骤

参考这个例子进行试验:

实验环境:Windows10 64bit, VS2010

我的具体步骤:

查看diff.dmp,具体信息如下

// Debug library initialized ...
E60000-E65FFF DBGHELP: mem_leak - private symbols & lines 
        .\mem_leak.pdb
77410000-77588FFF DBGHELP: ntdll - export symbols
75A40000-75B2FFFF DBGHELP: KERNEL32 - export symbols
76F60000-770D5FFF DBGHELP: KERNELBASE - export symbols
72E50000-72F0EFFF DBGHELP: MSVCR100 - export symbols
73480000-73502FFF DBGHELP: TmUmEvt - export symbols
76580000-76585FFF DBGHELP: PSAPI - export symbols
76C80000-76CC3FFF DBGHELP: SHLWAPI - export symbols
764C0000-7657DFFF DBGHELP: msvcrt - export symbols
76010000-761C9FFF DBGHELP: combase - export symbols
75E90000-75F3BFFF DBGHELP: RPCRT4 - export symbols
758E0000-758FDFFF DBGHELP: SspiCli - export symbols
758D0000-758D9FFF DBGHELP: CRYPTBASE - export symbols
75870000-758C8FFF DBGHELP: bcryptPrimitives - export symbols
75FC0000-76002FFF DBGHELP: sechost - export symbols
75BF0000-75D3CFFF DBGHELP: GDI32 - export symbols
75D50000-75E8FFFF DBGHELP: USER32 - export symbols
75F40000-75FBAFFF DBGHELP: ADVAPI32 - export symbols
76CD0000-76CFAFFF DBGHELP: IMM32 - export symbols
772F0000-7740FFFF DBGHELP: MSCTF - export symbols
731D0000-732BAFFF DBGHELP: tmmon - export symbols
74300000-74307FFF DBGHELP: VERSION - export symbols
//                                                                          
// Each log entry has the following syntax:                                 
//                                                                          
// + BYTES_DELTA (NEW_BYTES - OLD_BYTES) NEW_COUNT allocs BackTrace TRACEID 
// + COUNT_DELTA (NEW_COUNT - OLD_COUNT) BackTrace TRACEID allocations      
//     ... stack trace ...                                                  
//                                                                          
// where:                                                                   
//                                                                          
//     BYTES_DELTA - increase in bytes between before and after log         
//     NEW_BYTES - bytes in after log                                       
//     OLD_BYTES - bytes in before log                                      
//     COUNT_DELTA - increase in allocations between before and after log   
//     NEW_COUNT - number of allocations in after log                       
//     OLD_COUNT - number of allocations in before log                      
//     TRACEID - decimal index of the stack trace in the trace database     
//         (can be used to search for allocation instances in the original  
//         UMDH logs).                                                      
//                                                                          


+      32 (     32 -      0)      1 allocs  BackTrace9F3A48
+       1 (      1 -      0)    BackTrace9F3A48 allocations

    ntdll!RtlWalkHeap+188
    ntdll!WinSqmEventWrite+D7AE
    ntdll!RtlAllocateHeap+28
    tmmon!SleepMon+273AB
    MSVCR100!malloc+36
    mem_leak!wmain+1E (c:\users\xxx\documents\visual studio 2010\projects\mem_leak\mem_leak\mem_leak.cpp, 17)
    mem_leak!__tmainCRTStartup+122 (f:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c, 552)
    KERNEL32!BaseThreadInitThunk+24
    ntdll!RtlSetCurrentTransaction+D4
    ntdll!RtlSetCurrentTransaction+9F


Total increase ==     32 requested +     24 overhead =     56

发现+ 1 ( 1 - 0) BackTrace9F3A48 allocations。这说明有1次allocate内存未释放,还能从diff.dmp中,发现内存泄漏发生在mem_leak.cpp, 17行。

调试无内存泄漏问题的程序

经测试,如果申请的内存都被释放,diff.dmp中是不会出现这样的trace的。将这个例子main中代码改为如下:

int _tmain(int argc, _TCHAR* argv[])
{
    int i;
    scanf("%i", &i);//wait for mem leak
    int *x = getmem();//mem leak here
    free(x);
    scanf("%i", &i);//wait to exit
    return 0;
}

继续执行上面使用UMDH的10个步骤,发现diff.dmp中,出去注释,则只有如下一行有价值的信息:

Total decrease ==      0 requested +      0 overhead =      0

总结

使用GFlags和UMDH,可以用来发现Windows下C++程序的内存泄漏问题。
但UMDH在Win7中使用,自己一直报异常,我没能成功使用。反而在Win10下,UMDH使用正常。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值