在VC中用CRT库查找内存泄露

VC的C运行时库(C Run-Time Libraries, CRT库)中集成了非常完善的内存泄露调试功能,最近在使用此功能时发现网上的中文资料支离破碎,而且有些资料中还存在错误,为了方便大家查阅,特地整理出来放在这里。

本文内容来自 https://msdn.microsoft.com/en-us/library/x98tx3cf.aspx,按照自己的理解和验证情况重新做了整理,如果有和原文内容不符合的,以原始文章为准。

 

 

1、输出内存使用信息

 

首先要保证代码是在DEBUG模式下(定义有_DEBUG宏)编译和运行,在退出程序之前,调用 _CrtDumpMemoryLeaks(); 输出内存使用信息,如果存在内存泄露,会输出和泄露内存有关的数据,输出信息类似:

Detectedmemory leaks!

Dumpingobjects ->

{53}normal block at 0x00601558, 4 bytes long.

 Data: <   > CD CD CD CD

 

程序中可能有多个退出的位置,逐个做上述调用太麻烦而且容易出现遗漏,我们可以在程序起始的位置调用 _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); 上述语句的效果是自动在程序退出之前调用 _CrtDumpMemoryLeaks(); ,相当于在所有的程序出口添加了上面的调用。

 

2、输出泄露内存的申请位置

 

虽然确定了程序中存在内存泄露,而且可以知道泄露内存的长度及存储的数据信息,但是要定位具体的泄露位置还是有困难的,尤其是对于大型软件系统更是如此。如果能够定位到内存是在哪里申请的,可以大大方便我们确定产生内存泄露的原因。

对于C接口malloc申请的内存,在代码文件中包含下面的语句:

 

#define _CRTDBG_MAP_ALLOC

#include <stdlib.h>

#include <crtdbg.h>

 

注意:要严格按照上面的次序#include头文件,否则CRT库可能工作不正常。

 

这次我们得到的内存泄露信息包含了泄露内存申请的位置,类似:

Detectedmemory leaks!

Dumpingobjects ->

c:\test\test.cpp(21): {53} normal block at 0x00831558, 4 bytes long.

 Data: <   > CD CD CD CD

 

但是我们发现,上面的手段对C++中new操作申请的内存是无效的,如果要对new申请的内存也能够输出申请位置的信息,方法是在代码文件中包含下面的语句:

 

#ifdef_DEBUG

#ifndefDBG_NEW

#defineDBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )

#define newDBG_NEW

#endif

#endif

 

3、根据内存申请序号设置断点

 

上面的每个内存泄露信息中有用大括号包起来的内存申请序号 {53},表明这是程序申请的第53块内存,如果每次泄露的内存序号都是固定的,我们可以在申请该内存时设置断点,以进一步便于定位泄露原因。具体的步骤是:

(1)      在程序的起始位置设置断点,具体内容不限,保证在出问题的内存泄露之前即可

(2)      以调试方式执行程序,使程序停止在断点位置

(3)      在菜单debug / windows / watch打开任一watch窗口

在watch窗口的name栏,输入_crtBreakAlloc ;如果使用使用多线程DLL版本,原文说,需要输入  {,,ucrtbased.dll}_crtBreakAlloc,这个方法至少对vs2010是不通的,应改为  {,,msvcr100d.dll}_crtBreakAlloc,如果是其他版本的vc,相应的dll文件名也需要修改(这里介绍一个确定dll文件名的方法,调试模式下在debug窗口会有输出类似于 Loaded 'C:\Windows\System32\msvcr100d.dll',Symbols loaded. ,通过这个提示尝试可行的文件名);

(4)      在value栏中填入内存申请序号

(5)      继续以debug方式运行程序,在申请指定序号的内存时,会自动中断执行

 

除了手动在watch窗口中设置断点,我们还可以在代码中添加下面的语句来达到同样的目的:

_crtBreakAlloc = 52; 或者

_CrtSetBreakAlloc(52);

 

4、统计和比较内存状态

 

可以通过下面的调用,在程序的任何位置生成当前内存使用情况的快照,

_CrtMemState s1;
_CrtMemCheckpoint( &s1 );
 
执行 _CrtMemDumpStatistics( &s1 ); 可以输出快照信息,如下:
 
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
3071 bytes in 16 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 3071 bytes.
Total allocations: 3764 bytes.

 

 

如果我们怀疑在某段代码中存在内存泄露,可以在这段代码之前和之后分别生成内存快照,并比较两个内存快照的差异,方法是:

if ( _CrtMemDifference( &s3, &s1, &s2) )
   _CrtMemDumpStatistics( &s3 );

输出的信息类似:

0 bytesin 0 Free Blocks.

8 bytesin 2 Normal Blocks.

0 bytesin 0 CRT Blocks.

0 bytesin 0 Ignore Blocks.

0 bytesin 0 Client Blocks.

Largestnumber used: 0 bytes.

Totalallocations: 8 bytes.

 

可以看出,在两个快照相差了2个内存块共8个字节,此信息有助于分析产生内存泄露的原因。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值