转自:VS环境中进行内存泄漏的检测 - 星辰风 - 博客园

根据MSDN中的介绍,亲测整理。

本篇比较长,如不愿花费太多时间,可只看第一段和第四段,甚至只看第四段。

内存泄漏,即未能正确释放以前分配的内存,是 C/C++ 应用程序中最难以捉摸也最难以检测到的 Bug 之一。借助 Visual Studio 调试器和 C 运行时 (CRT) 库,可以检测和识别内存泄漏。检测内存泄漏的主要工具是调试器和 C 运行库 (CRT) 调试堆函数。

简单的使用

要调用CRT调试堆函数,需包含头文件<crtdbg.h>。

在程序的退出点之前调用函数

_CrtDumpMemoryLeaks

();可简单的显示内存泄漏报告。
示例:

#include "stdlib.h"
#include <crtdbg.h>
int main()
{char *p =new char[30];char *p1=(char *)malloc(sizeof(char)*10);_CrtDumpMemoryLeaks();return 0;
}

输出结果:

当程序有多个退出点时,在每一个退出点都调用_CrtDumpMemoryLeaks()显然不是一个好主意,在程序的开头部分调用函数_CrtSetDbgFlag会导致在每个退出点自动调用 _CrtDumpMemoryLeaks。如此调用_CrtSetDbgFlag必须设置两个位域

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

解释内存泄漏报告

{64}—— 表示是在第64次分配的内存,最终没有被释放掉,从而导致泄漏。CRT 报告包含运行 过程中的所有内存块分配情况。其中包括 CRT 库和其他库(如 MFC)的分配情况。 所以不要疑惑这里为什么不是2.

Normal block—— 表示被泄露的内存块为由程序分配的普通内存。另外,这个值还有可能是

Client Blocks ,“客户端块”是由 MFC 程序用于需要析构函数的对象的特殊 类型内存块。 MFC new 运算符根据正在创建的对象的需要创建普通块或客 户端块。

0x004C1DA0—— 表示发生泄漏的内存位置

10 bytes long.—— 遭泄露的内存块的大小

Data: < > CD CD CD CD CD CD CD CD CD CD —— 遭泄露的块中的数据,一般只显示前16个字节

上述内存泄漏报告确实给出了不少信息,但很重要的一点却没有给出,那就是发生泄漏的代码位置,毕竟我们需要据此来改善代码。

获取更详细的内存泄漏报告

对于堆函数(例如 malloc、 free、 calloc、 realloc、 new 和 delete)都有其对应的调试版本,如果在检测内存泄漏的过程中使用这些堆函数的调试版本,则可以输出更详细的内存泄漏报告。这
并不难。

通过定义宏_CRTDBG_MAP_ALLOC可以使malloc,free等函数映射到它们的调试版本。

对于C++中的new和delete操作符,稍麻烦点,需要重新定义 new 才能在内存泄漏报告中看到文件和行号。

#ifdef _DEBUG

#ifndef DBG_NEW

#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )

#define new DBG_NEW

#endif

#endif // _DEBUG

示例:

#define _CRTDBG_MAP_ALLOC
#include "stdlib.h"
#include <crtdbg.h>#ifdef _DEBUG#ifndef DBG_NEW#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )#define new DBG_NEW#endif
#endif  // _DEBUG
int main()
{_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF |         \            _CRTDBG_LEAK_CHECK_DF );char *p =new char[30];char *p1=(char *)malloc(sizeof(char)*10);
//    _CrtDumpMemoryLeaks();return 0;
}

输出结果:

至此,已经足够满足我们基本的需求了。

需要注意的一点是,宏_CRTDBG_MAP_ALLOC的定义必须放在include< crtdbg.h >之前,这表示在编译crtdbg.h时,会根据这个宏来选择编译上述堆函数的Debug版本。


锁定内存泄漏位置的另一个办法是在内存分配编号上设置断点。

1. 在应用程序的起点附近设置断点,然后启动应用程序。

2. 当应用程序在断点处中断时,会出现 “监视”窗口。

3. 在 “监视”窗口中,在 “名称”列中键入 _crtBreakAlloc。

4. 如果要使用 CRT 库的多线程 DLL 版本(/MD 选项),请加入上下文运算符: {,,msvcr100d.dll}_crtBreakAlloc(针对vs2010是msvcr100d.dll,其他版本的环境找对应的dll)

5. 在 “值”列中,将显示的值替换为要在其位置中断的内存分配的分配编号。

与其相似的另一个做法是在代码中设置内存分配断点。具体做法时在代码的起始位置附近,调用如下函数(其实是个宏):

_CrtSetBreakAlloc(61);

参数61表示内存分配的分配编号,可由上述简单的使用获得。

这一下,我们获得了更多详细的报告——调用堆栈,可以更准确的锁定发生内存泄漏的位置。但这种方法的不足之处是,对于在多线程代码中,由于每次调试时的内存分配编号都会变化,就没法使用这种办法了。


定位内存泄漏的另一种技术涉及在关键点对应用程序的内存状态拍快照。

若要为应用程序中给定点的内存状态拍快照,请创建 _CrtMemState 结构,将它传递给 _CrtMemCheckpoint 函数。

该函数用当前内存状态的快照填充此结构:

_CrtMemState s1;

_CrtMemCheckpoint( &s1 );

若要输出 _CrtMemState 结构的内容,请将该结构传递给 _ CrtMemDumpStatistics 函数:

_CrtMemDumpStatistics( &s1 );

若要确定在某个代码部分中是否发生了内存泄漏,可以对这部分之前和之后的内存状态拍快照,然后使用 _CrtMemDifference 比较两个状态:

_CrtMemCheckpoint( &s1 );

// memory allocations take place here

_CrtMemCheckpoint( &s2 );

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

_CrtMemDumpStatistics( &s3 );

示例代码

#include "stdlib.h"
#include <crtdbg.h>
#include <Windows.h>
int main()
{_CrtMemState s1;_CrtMemState s4;_CrtMemCheckpoint( &s1 );OutputDebugString("第一次内存快照\n");_CrtMemDumpStatistics(&s1);char *p =new char[30];_CrtMemState s2;_CrtMemCheckpoint( &s2 );OutputDebugString("第二次内存快照\n");_CrtMemDumpStatistics(&s2);if ( _CrtMemDifference( &s4, &s1, &s2) ){    OutputDebugString("前两次内存快照的差异\n");_CrtMemDumpStatistics( &s4 );}char *p1=(char *)malloc(sizeof(char)*10);_CrtMemState s3;_CrtMemCheckpoint( &s3 );OutputDebugString("第三次内存快照\n");_CrtMemDumpStatistics(&s3);if ( _CrtMemDifference( &s4, &s1, &s3) ){    OutputDebugString("首尾内存快照的差异\n");_CrtMemDumpStatistics( &s4 );}return 0;
}

普通块是由程序分配的普通内存。

客户端块是由 MFC 程序用于需要析构函数的对象的特殊类型内存块。

MFC new 运算符根据正在创建的对象的需要创建普通块或客户端块。

“CRT 是由 CRT 库为自己使用而分配的内存块。

CRT 库可处理这些块的释放。

因此,不大可能在内存泄漏报告中看到这些块,除非出现严重错误(例如 CRT 库损坏)。

内存泄漏报告中绝对不会出现另外两个内存块类型。

可用块是已释放的内存。

也就是说,根据定义,这种块不会泄漏。

忽略块是已明确标记、不出现在内存泄漏报告中的块。

寻找内存泄漏的一个方法是,首先在应用程序的开头和结尾部分放置 _CrtMemCheckpoint 调用,然后使用 _CrtMemDifference 比较两个结果。

如果 _CrtMemDifference 显示有内存泄漏,可以添加更多 _CrtMemCheckpoint 来进一步找到泄漏源。

这个方法看起来真够笨拙的,不过它或许有别的好处吧。谁知道呢?


使用第三方工具

或许有人会嫌上述方法都太麻烦了,那不妨试试第三方工具,目前用于检测内存泄漏的第三方工具可谓多种多样,这里只推荐一款用与vs环境的第三方插件:Visual Leak Detector ,推荐理由:开源,免费。

下载地址:CodePlex Archive

目前已更新版本至v2.4rc2

使用方法及效果如下:

其调用堆栈的分析在控制台应用上并不十分准确,忽略了我们最关注的源代码文件中调用位置。不过其在MFC中的表现还不赖。

以上源自 在Visual Studio 2010中使用Visual Leak Detector_辛亚平的专栏-CSDN博客,话说这个blog里确实有很多好东西。

昨夜星辰昨夜风,画楼西畔桂堂东。 身无彩凤双飞翼,心有灵犀一点通。 隔座送钩春酒暖,分曹射覆蜡灯红。 嗟余听鼓应官去,走马兰台类转蓬。

VS环境中进行内存泄漏的检测相关推荐

  1. 监视和检测Java应用程序中的内存泄漏

    因此,您的应用程序内存不足,您日夜不停地分析应用程序,以期捕获对象中的内存漏洞. 后续步骤将说明如何监视和检测您的内存泄漏,以确保您的应用程序安全. 1.怀疑内存泄漏 如果您怀疑有内存泄漏,可以使用一 ...

  2. OpenCV中的内存泄漏检测

    转自:http://chaishushan.blog.163.com/blog/static/130192897200911685559809/ 内存泄漏时程序开发中经常遇到的问题. 而且出现内存泄漏 ...

  3. 浅谈C++中内存泄漏的检测

    首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复. 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsCheck,功能非常强大,相信做C++开发的 ...

  4. C++中内存泄漏的检测

           好喝来自        首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复. 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsChe ...

  5. C++中内存泄漏的检测方法介绍

    本文介绍C++中内存泄漏的检测方法. 首先我们需要知道程序有没有内存泄露,然后定位到底是哪行代码出现内存泄露了,这样才能将其修复. 最简单的方法当然是借助于专业的检测工具,比较有名如BoundsChe ...

  6. python内存泄漏_诊断和修复Python中的内存泄漏

    python内存泄漏 Fugue uses Python extensively throughout the Conductor and in our support tools, due to i ...

  7. java内存泄漏怎么检测_JAVA内存泄漏原因和内存泄漏检测工具

    JAVA内存泄漏原因和内存泄漏检测工具 摘要 虽然Java 虚拟机(JVM)及其垃圾收 集器(garbage collector,GC)负责管理大多数的内存任务,Java 软件程序中还是有可能出现内 ...

  8. 内存泄漏的检测、定位和解决经验总结

    内存泄漏的检测.定位和解决经验总结 温辉敏(wenhm@sina.com) 2006 年 05 月 [摘要] 结合局端MCU项目中CSS.NMS模块内存泄漏检测.修正的过程,简要介绍了内存泄漏检测的工 ...

  9. VS C/C++控制台程序添加内存泄漏自动检测功能

    基于MFC框架的应用程序由模板生成时,已经自动添加了内存泄漏自动检测功能,当你的程序有内存泄漏,在Debug调式模式下运行就会在vc的输出窗口里显示出来,容易发现并及时解决.但是我们在写一些测试程序时 ...

最新文章

  1. 神经网络 debug 太难了,这里有六个实用技巧
  2. 如何有效防止域名被电信服务商劫持(电信114弹窗广告)
  3. 基于Dockerfile 构建redis5.0.0(包括持久化)及RedisDestopManager 监控
  4. thinkphp5.0.9预处理导致的sql注入复现与详细分析
  5. PageLayoutControl的基本操作
  6. 记录——《C Primer Plus (第五版)》第九章编程练习第六题
  7. div中文字居中加粗
  8. Win11怎么查看设备管理器?Win11设备管理器在哪里打开?
  9. Matlab 终止正在运行的程序
  10. asp.net 按钮点击调用FileUpload
  11. 群接龙,JK上报一键化手机脚本autojs
  12. 手机怎么打开html.chm,chm格式文件怎么打开,华为手机chm阅读器哪个好
  13. 超声成像突破衍射极限,有望检测肿瘤
  14. [深度学习概念]·非极大值抑制解析
  15. ASP.NET实现日期转为大写的汉字
  16. VMware vCenter Converter Standalone
  17. [BZOJ2177][最小/最大(曼哈顿距离)生成树]曼哈顿最小生成树
  18. qq修改群名服务器失败,qq建群失败什么原因 q群一直创建失败 - 云骑士一键重装系统...
  19. 崩坏3服务器维护2月8号,《崩坏3》2月8日更新内容 符华月轮正式上线
  20. python_numpy_计算对数收益率和还原问题

热门文章

  1. win10 office activation tools
  2. Vue 动态赋值 class
  3. 软件工程的经验分享(来自一位前辈的经验)
  4. 2018第二届中国移动金融发展大会
  5. deepinv2 添加打印机_如何在Deepin 20下安装brother打印机驱动及设置网络打印机?...
  6. No converter for [class xxx] Content-Type ‘appliction/octet-stream;charset=UTF-8‘ 的解决办法
  7. 水利类计算机就业情况,2020年水利水电工程专业就业前景分析 _ 一堂课
  8. 惠普台式计算机型号怎么看,如何查看惠普笔记本型号?惠普笔记本型号以及小型号查看方法...
  9. Excel数据分析:美国牛油果销售分析
  10. mysql 2000 无法安装_MySQL在Win2000下的安装_MySQL