如何在VC++ 6.0中启用内存泄漏检测?

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情
VC++ IDE 的默认状态是没有启用内存泄漏检测机制的,也就是说即使某段代码有内存泄漏,调试会话的 Output 窗口的 Debug 页不会输出有关内存泄漏信息。你必须设定两个最基本的机关来启用内存泄漏检测机制。

  一是使用调试堆函数:

  #define _CRTDBG_MAP_ALLOC
  #include <stdlib.h>
  #include <crtdbg.h>

  注意:#include 语句的顺序。如果更改此顺序,所使用的函数可能无法正确工作。

  通过包含 crtdbg.h 头文件,可以将 malloc 和 free 函数映射到其“调试”版本 _malloc_dbg 和 _free_dbg,这些函数会跟踪内存分配和释放。此映射只在调试(Debug)版本(也就是要定义 _DEBUG)中有效。发行版本(Release)使用普通的 malloc 和 free 函数。
  #define 语句将 CRT 堆函数的基础版本映射到对应的“调试”版本。该语句不是必须的,但如果没有该语句,那么有关内存泄漏的信息会不全。

  二是在需要检测内存泄漏的地方添加下面这条语句来输出内存泄漏信息:

  _CrtDumpMemoryLeaks();

  当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在 Output 窗口的 Debug 页中显示内存泄漏信息。比如:

  Detected memory leaks!
  Dumping objects ->
  C:/Temp/memleak/memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.
  Data: <AB> 41 42
  c:/program files/microsoft visual studio/vc98/include/crtdbg.h(552) : {44} normal block at 0x00441BD0, 33 bytes long.
  Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
  c:/program files/microsoft visual studio/vc98/include/crtdbg.h(552) : {43} normal block at 0x00441C20, 40 bytes long.
  Data: < C > 08 02 43 00 16 00 00 00 00 00 00 00 00 00 00 00
  Object dump complete.

  如果不使用 #define _CRTDBG_MAP_ALLOC 语句,内存泄漏的输出是这样的:

  Detected memory leaks!
  Dumping objects ->
  {45} normal block at 0x00441BA0, 2 bytes long.
  Data: <AB> 41 42
  {44} normal block at 0x00441BD0, 33 bytes long.
  Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
  {43} normal block at 0x00441C20, 40 bytes long.
  Data: < C > C0 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00
  Object dump complete.

  根据这段输出信息,你无法知道在哪个源程序文件里发生了内存泄漏。下面我们来研究一下输出信息的格式。第一行和第二行没有什么可说的,从第三行开始:

  {xx}:花括弧内的数字是内存分配序号,本文例子中是 {45},{44},{43};
  block:内存块的类型,常用的有三种:normal(普通)、client(客户端)或 CRT(运行时);本文例子中是:normal block;
  用十六进制格式表示的内存位置,如:at 0x00441BA0 等;
  以字节为单位表示的内存块的大小,如:32 bytes long;
  前 16 字节的内容(也是用十六进制格式表示),如:Data: <AB> 41 42 等;

  仔细观察不难发现,如果定义了 _CRTDBG_MAP_ALLOC ,那么在内存分配序号前面还会显示在其中分配泄漏内存的文件名,以及文件名后括号中的数字表示发生泄漏的代码行号,比如:

  C:/Temp/memleak/memleak.cpp(15)

  双击 Output 窗口中此文件名所在的输出行,便可跳到源程序文件分配该内存的代码行(也可以选中该行,然后按 F4,效果一样) ,这样一来我们就很容易定位内存泄漏是在哪里发生的了,因此,_CRTDBG_MAP_ALLOC 的作用显而易见。

使用 _CrtSetDbgFlag

  如果程序只有一个出口,那么调用 _CrtDumpMemoryLeaks 的位置是很容易选择的。但是,如果程序可能会在多个地方退出该怎么办呢?在每一个可能的出口处调用 _CrtDumpMemoryLeaks 肯定是不可取的,那么这时可以在程序开始处包含下面的调用:

  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

  这条语句无论程序在什么地方退出都会自动调用 _CrtDumpMemoryLeaks。注意:这里必须同时设置两个位域标志:_CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF。

设置 CRT 报告模式

  默认情况下,_CrtDumpMemoryLeaks 将内存泄漏信息 dump 到 Output 窗口的 Debug 页, 如果你想将这个输出定向到别的地方,可以使用 _CrtSetReportMode 进行重置。如果你使用某个库,它可能将输出定向到另一位置。此时,只要使用以下语句将输出位置设回 Output 窗口即可:

  _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );

  有关使用 _CrtSetReportMode 的详细信息,请参考 MSDN 库关于 _CrtSetReportMode 的描述。

解释内存块类型

  前面已经说过,内存泄漏报告中把每一块泄漏的内存分为 normal(普通块)、client(客户端块)和 CRT 块。事实上,需要留心和注意的也就是 normal 和 client,即普通块和客户端块。

  ·normal block(普通块):这是由你的程序分配的内存。
  ·client block(客户块):这是一种特殊类型的内存块,专门用于 MFC 程序中需要析构函数的对象。MFC new 操作符视具体情况既可以为所创建的对象建立普通块,也可以为之建立客户块。
  ·CRT block(CRT 块):是由 C RunTime Library 供自己使用而分配的内存块。由 CRT 库自己来管理这些内存的分配与释放,我们一般不会在内存泄漏报告中发现 CRT 内存泄漏,除非程序发生了严重的错误(例如 CRT 库崩溃)。

  除了上述的类型外,还有下面这两种类型的内存块,它们不会出现在内存泄漏报告中:

  ·free block(空闲块):已经被释放(free)的内存块。
  ·gnore block(忽略块):这是程序员显式声明过不要在内存泄漏报告中出现的内存块。

如何在内存分配序号处设置断点?


  在内存泄漏报告中,的文件名和行号可告诉分配泄漏的内存的代码位置,但仅仅依赖这些信息来了解完整的泄漏原因是不够的。因为一个程序在运行时,一段分 配内存的代码可能会被调用很多次,只要有一次调用后没有释放内存就会导致内存泄漏。为了确定是哪些内存没有被释放,不仅要知道泄漏的内存是在哪里分配的, 还要知道泄漏产生的条件。这时内存分配序号就显得特别有用——这个序号就是文件名和行号之后的花括弧里的那个数字。
  例如,在本文例子代码的输出信息中,“45”是内存分配序号,意思是泄漏的内存是你程序中分配的第四十五个内存块:

  Detected memory leaks!
  Dumping objects ->
  C:/Temp/memleak/memleak.cpp(15) : {45} normal block at 0x00441BA0, 2 bytes long.
  Data: <AB> 41 42
  ......
  Object dump complete.

  CRT 库对程序运行期间分配的所有内存块进行计数,包括由 CRT 库自己分配的内存和其它库(如 MFC)分配的内存。因此,分配序号为 N 的对象即为程序中分配的第 N 个对象,但不一定是代码分配的第 N 个对象。(大多数情况下并非如此。)
  这样的话,你便可以利用分配序号在分配内存的位置设置一个断点。方法是在程序起始附近设置一个位置断点。当程序在该点中断时,可以从 QuickWatch(快速监视)对话框或 Watch(监视)窗口设置一个内存分配断点:

  例如,在 Watch 窗口中,在 Name 栏键入下面的表达式:

  _crtBreakAlloc

  如果要使用 CRT 库的多线程 DLL 版本(/MD 选项),那么必须包含上下文操作符,像这样:

  如果你正在使用 Visual C++ 4.0 or 4.1,这样写:
  {,,msvcr40d.dll}*__p__crtBreakAlloc()
  如果你正在使用 Visual C++ 4.2 或更高版本,这样写:
  {,,msvcrtd.dll}*__p__crtBreakAlloc()

  现在按下回车键,调试器将计算该值并把结果放入 Value 栏。如果没有在内存分配点设置任何断点,该值将为–1。
  用你想要在其位置中断的内存分配的分配序号替换 Value 栏中的值。例如输入 45。这样就会在分配序号为 45 的地方中断。
  在所感兴趣的内存分配处设置断点后,可以继续调试。这时,运行程序时一定要小心,要保证内存块分配的顺序不会改变。当程序在指定的内存分配处中断时, 可以查看 Call Stack(调用堆栈)窗口和其它调试器信息以确定分配内存时的情况。如果必要,可以从该点继续执行程序,以查看对象发生了什么情况,或许可以确定未正确 释放对象的原因。
  尽管通常在调试器中设置内存分配断点更方便,但如果愿意,也可在代码中设置这些断点。为了在代码中设置一个内存分配断点,可以增加这样一行(对于第四十五个内存分配):

  _crtBreakAlloc = 45;

  你还可以使用有相同效果的 _CrtSetBreakAlloc 函数:

  _CrtSetBreakAlloc(45);

如何比较内存状态?


  定位内存泄漏的另一个方法就是在关键点获取应用程序内存状态的快照。CRT 库提供了一个结构类型 _CrtMemState。你可以用它来存储内存状态的快照:

  _CrtMemState s1, s2, s3;

  若要获取给定点的内存状态快照,可以向 _CrtMemCheckpoint 函数传递一个 _CrtMemState 结构。该函数用当前内存状态的快照填充此结构:

  _CrtMemCheckpoint( &s1 );

  通过向 _CrtMemDumpStatistics 函数传递 _CrtMemState 结构,可以在任意地方 dump 该结构的内容:

  _CrtMemDumpStatistics( &s1 );

  该函数输出如下格式的 dump 内存分配信息:
  0 bytes in 0 Free Blocks.
  75 bytes in 3 Normal Blocks.
  5037 bytes in 41 CRT Blocks.
  0 bytes in 0 Ignore Blocks.
  0 bytes in 0 Client Blocks.
  Largest number used: 5308 bytes.
  Total allocations: 7559 bytes.

  若要确定某段代码中是否发生了内存泄漏,可以通过获取该段代码之前和之后的内存状态快照,然后使用 _CrtMemDifference 比较这两个状态:

  _CrtMemCheckpoint(&s1); // 获取第一个内存状态快照

  // 在这里进行内存分配
  .........................................

  _CrtMemCheckpoint(&s2); // 获取第二个内存状态快照

  // 比较两个内存快照的差异
  if( _CrtMemDifference(&s3, &s1, &s2))
  {
    _CrtMemDumpStatistics(&s3); // dump 差异结果
  }

  顾名思义,_CrtMemDifference 比较两个内存状态(前两个参数),生成这两个状态之间差异的结果(第三个参数)。在程序的开始和结尾放置 _CrtMemCheckpoint 调用,并使用 _CrtMemDifference 比较结果,是检查内存泄漏的另一种方法。如果检测到泄漏,则可以使用 _CrtMemCheckpoint 调用通过二进制搜索技术来分割程序和定位泄漏。

结论

  尽管 VC ++ 具有一套专门调试 MFC 应用程序的机制,但本文上述讨论的内存分配很简单,没有涉及到 MFC 对象,所以这些内容同样也适用于 MFC 程序。在 MSDN 库中可以找到很多有关 VC++ 调试方面的资料,如果你能善用 MSDN 库,相信用不了多少时间你就有可能成为调试高手。 
mfc mysql释放_关于MFC下检查和消除内存泄露的技巧 作者:freepublic 摘要: 本人菜鸟,测试过,但是不怎么明白,保留做以后研究 本文分析了Windows环境使用MFC调试内存泄露的技术,介绍了在Windows环境下用VC查找,定位和消除内存泄露的方法技巧。 关键词:VC;CRT 调试堆函数;试探法。 编译环境 VC6.0 技术作者:freepublic摘要:本人菜鸟,测试过,但是不怎么明白,保留做以后研究本文分析了Windows环境使用M... 阅读详情

相关推荐

操作系统内存管理实验:深入VC6.0内存机制

本文还有配套的精品资源,点击获取 简介:操作系统作为计算机的核心,其内存管理功能确保了多任务执行的效率和稳定性。本实验通过VC6.0开发环境,深入探讨内存分配、释放、对齐、虚拟内存、保护、碎片以及堆栈管理等关键内存管理知识点。学生将通过编码实践,如实现内存分配器和设计虚拟内存系统,以提升对操作系统内存管理理论和实际操作的理解。 1. 操作系统内存管理概述 1...

weixin_32306683的博客 1513

VC6.0辅助插件-检查内存泄露的工具

注明的内存泄露和其他错误检查工具,希望大家喜欢,VC6.0使用需要打SP6补丁。

VC6 内存泄漏检测

利用VC++6.0撰写内存泄漏检测的方法

VC++6程序内存泄露的发现与预防

 题目给的太大:P指针是个好东西,就是以不注意就会忘记delete,造成内存泄露。检查内存泄漏的方法和简单运行完程序后,在OouPut窗口会提示 Detected memory leaks!Dumping objects ->{223} normal block at 0x003CF650, 4 bytes long.Data: E8 F6 3C 00 {221} normal bl

达中的专栏 1367

VC++6.0 内存泄露调试

VC++6.0 内存泄露调试1、使用VC6自带的内存泄露调试工具2、使用Visual Lead Detector调试内存泄露 最近使用VC6进行项目的开发,项目稍大,而且有严重的内存泄露问题,解决问题的过程中总结了一些内存泄露调试的方法,在此记录下学习成果,也希望能对别人有所帮助。 1、使用VC6自带的内存泄露调试工具 在想要调试的cpp文件中添加如下代码: #ifdef _DEBUG #define new DEBUG_NEW #endif 可能存在的问题:error C2065: ‘DEBUG_NEW

qq_41940438的博客 716

VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏

【转贴】VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏 下载例子源代码  最近看了周星星 Blog 中的一篇文章:“VC++6.0内存泄漏检测”,受益匪浅,便运行其例子代码想看看 Output 窗口中的输出结果,可惜怎么弄其输出都不是预期的东西,郁闷了半天,便到水坛里找到周星星,请求他指点一、二,然而未果。没有办

sophia_sy的专栏 1597

CRT检测内存泄漏

VC++ 6.0 中如何使用 CRT调试功能来检测内存泄漏载例子源代码http://www.vckbase.com/code/envdebug/debug/myleaktest.rar最近看了周星星 Blog 中的一篇文章:“VC++6.0内存泄漏检测”,受益匪浅,便运行其例子代码想看看 Output 窗口中的输出结果,可惜怎么弄其输出都不是预期的东西,郁闷了半天,便到水坛里找到周星

文逗 1233

使用 CRT 调试功能来检测内存泄漏

VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏 作者:JerryZ http://www.vckbase.com/document/viewdoc/?id=1349   最近看了周星星 Blog 中的一篇文章:“VC++6.0内存泄漏检测”,受益匪浅,便运行其例子代码想看看 Output 窗口中的输出结果,可惜怎么弄其输出都不是预期的东西,郁闷了半天,便到水坛里找

_Witch__的专栏 922

关于MFC下检查和消除内存泄露的技巧

编译环境 VC++6.0 技术原理 检测内存泄漏的主要工具是调试器和 CRT 调试堆函数。若要启用调试堆函数,请在程序中包括以下语句: 1.#define CRTDBG_MAP_ALLOC 2.#include 3.#include 注意 #include 语句必须采用上文所示顺序。如果更改了顺序,所使用的函数可能无法正确工

Never too late to study 1267

内存泄露简单解决办法

编译环境 VC++6.0 技术原理 检测内存泄漏的主要工具是调试器和 CRT 调试堆函数。若要启用调试堆函数,请在程序中包括以下语句:  #define CRTDBG_MAP_ALLOC #include &lt;stdlib.h&gt; #include &lt;crtdbg.h&gt; 注意 #include 语句必须采用上文所示顺序。如果更改了顺序,所使用的函数可能无法正确工作。  通过包括...

zhang1150720003的博客 419

VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏(转)

VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏作者:JerryZ下载例子源代码  最近看了周星星 Blog 中的一篇文章:“VC++6.0内存泄漏检测”,受益匪浅,便运行其例子代码想看看 Output 窗口中的输出结果,可惜怎么弄其输出都不是预期的东西,郁闷了半天,便到水坛里找到周星星,请求他指点一、二,然而未果。没有办法,最后我一头栽进 MSDN 库狂搜了一把,功夫不负有心人

bairny的专栏 1万+

VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏 调试方法

VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏 作者:JerryZ 下载例子源代码   最近看了周星星 Blog 中的一篇文章:“VC++6.0内存泄漏检测”,受益匪浅,便运行其例子代码想看看 Output 窗口中的输出结果,可惜怎么弄其输出都不是预期的东西,郁闷了半天,便到水坛里找到周星星,请求他指点一、二,然而未果。没有办法,最后我一头栽进 MSDN 库狂搜了

yxnyxnyxnyxnyxn的专栏 2892

vc++内存泄漏检测

vc++内存泄漏检测

huangyimin的专栏 1385

VC++6.0内存泄漏检测(转)

转自:http://blog.vckbase.com/bruceteen/archive/2004/10/28/1130.aspx这篇文章是对2004-09-02日发表的《VC++6.0中简单的内存泄漏检测事例代码》(已经删除)的更新.C++代码而言,内存泄漏问题虽然有诸多方法避免,但实际代码编写的时候,或出于自信或出于复杂性的考虑,常常还会用到原始的operator new,这不可避免的会

bairny的专栏 1221
上一篇: 浅谈C/C++内存泄漏及其检测工具
下一篇: 使用调试器和CRT库来查找内存泄漏
primer_programer
博客等级 码龄20年 283粉丝 180原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值