您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏
您还未登录!|登录|注册|帮助CSDN首页资讯论坛博客下载搜索更多bairny的专栏目录视图摘要视图订阅公告:CSDN博客积分系统正式上线!VC++6.0中如何使用CRT调试功能来检测内存泄漏(转)2007-05-1715:564183人阅读评论(1)收藏举报VC++6.0中如何使用CRT调试功能来检测内存泄漏作者:JerryZ下载例子源代码最近看了周星星Blog中的一篇文章:“VC++6.0中内存泄漏检测”,受益匪浅,便运行其例子代码想看看Output窗口中的输出结果,可惜怎么弄其输出都不是预期的东西,郁闷了半天,便到水坛里找到周星星,请求他指点一、二,然而未果。没有办法,最后我一头栽进MSDN库狂搜了一把,功夫不负有心人,我搜出很多有关这方面的资料,没过多久我便基本上就找到了答案......首先,检测内存泄漏的基本工具是调试器和CRT调试堆函数。为了使用调试堆函数,必须在要检测内存泄漏和调试的程序中添加下面的语句:#define_CRTDBG_MAP_ALLOC#includestdlib.h#includecrtdbg.h#includedebug_new.hMSDN如是说:“必须保证上面声明的顺序,如果改变了顺序,可能不能正常工作。”至于这是为什么,我们不得而知。MS的老大们经常这样故弄玄虚。针对非MFC程序,再加上周星星的头文件:debug_new.h,当然如果不加这一句,也能检测出内存泄漏,但是你无法确定在哪个源程序文件中发生泄漏。Output输出只告诉你在crtsdb.h中的某个地方有内存泄漏。我测试时REG_DEBUG_NEW没有起作用。加不加这个宏都可以检测出发生内存分配泄漏的文件。其次,一旦添加了上面的声明,你就可以通过在程序中加入下面的代码来报告内存泄漏信息了:_CrtDumpMemoryLeaks();这就这么简单。我在周星星的例子代码中加入这些机关后,在VC++调试会话(按F5调试运行)Output窗口的Debug页便看到了预期的内存泄漏dump。该dump形式如下:Detectedmemoryleaks!Dumpingobjects-c:/ProgramFiles/.../include/crtdbg.h(552):{45}normalblockat0x00441BA0,2byteslong.Data:AB4142c:/ProgramFiles/.../include/crtdbg.h(552):{44}normalblockat0x00441BD0,33byteslong.Data:C004300CDCDCDCDCDCDCDCDCDCDCDCDCDc:/ProgramFiles/.../include/crtdbg.h(552):{43}normalblockat0x00441C20,40byteslong.Data:CE8014300160000000000000000000000Objectdumpcomplete.更具体的细节请参考本文附带的源代码文件。下面是我看过MSDN资料后,针对“如何使用CRT调试功能来检测内存泄漏?”的问题进行了一番编译和整理,希望对大家有用。如果你的英文很棒,那就不用往下看了,建议直接去读MSDN库中的技术原文。C/C++编程语言的最强大功能之一便是其动态分配和释放内存,但是中国有句古话:“最大的长处也可能成为最大的弱点”,那么C/C++应用程序正好印证了这句话。在C/C++应用程序开发过程中,动态分配的内存处理不当是最常见的问题。其中,最难捉摸也最难检测的错误之一就是内存泄漏,即未能正确释放以前分配的内存的错误。偶尔发生的少量内存泄漏可能不会引起我们的注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种各样的征兆:从性能不良(并且逐渐降低)到内存完全耗尽。更糟的是,泄漏的程序可能会用掉太多内存,导致另外一个程序垮掉,而使用户无从查找问题的真正根源。此外,即使无害的内存泄漏也可能殃及池鱼。幸运的是,VisualStudio调试器和C运行时(CRT)库为我们提供了检测和识别内存泄漏的有效方法。下面请和我一起分享收获——如何使用CRT调试功能来检测内存泄漏?1.如何启用内存泄漏检测机制?o使用_CrtSetDbgFlago设置CRT报告模式2.解释内存块类型3.如何在内存分配序号处设置断点?4.如何比较内存状态?5.结论如何启用内存泄漏检测机制?VC++IDE的默认状态是没有启用内存泄漏检测机制的,也就是说即使某段代码有内存泄漏,调试会话的Output窗口的Debug页不会输出有关内存泄漏信息。你必须设定两个最基本的机关来启用内存泄漏检测机制。一是使用调试堆函数:#define_CRTDBG_MAP_ALLOC#includestdlib.h#includecrtdbg.h注意:#include语句的顺序。如果更改此顺序,所使用的函数可能无法正确工作。通过包含crtdbg.h头文件,可以将malloc和free函数映射到其“调试”版本_malloc_dbg和_free_dbg,这些函数会跟踪内存分配和释放。此映射只在调试(Debug)版本(也就是要定义_DEBUG)中有效。发行版本(Release)使用普通的malloc和free函数。#define语句将CRT堆函数的基础版本映射到对应的“调试”版本。该语句不是必须的,但如果没有该语句,那么有关内存泄漏的信息会不全。二是在需要检测内存泄漏的地方添加下面这条语句来输出内存泄漏信息:_CrtDumpMemoryLeaks();当在调试器下运行程序时,_CrtDumpMemoryLeaks将在Output窗口的Debug页中显示内存泄漏信息。比如:Detectedmemoryleaks!Dumpingobjects-C:/Temp/memleak/memleak.cpp(15):{45}normalblockat0x00441BA0,2byteslong.Data:AB4142c:/programfiles/microsoftvisualstudio/vc98/include/crtdbg.h(552):{44}normalblockat0x00441BD0,33byteslong.Data:C004300CDCDCDCDCDCDCDCDCDCDCDCDCDc:/programfiles/microsoftvisualstudio/vc98/include/crtdbg.h(552):{43}normalblockat0x00441C20,40byteslong.Data:C08024300160000000000000000000000Objectdumpcomplete.如果不使用#define_CRTDBG_MAP_ALLOC语句,内存泄漏的输出是这样的:Detectedmemoryleaks!Dumpingobjects-{45}normalblockat0x00441BA0,2byteslong.Data:AB4142{44}normalblockat0x00441BD0,33byteslong.Data:C004300CDCDCDCDCDCDCDCDCDCDCDCDCD{43}normalblockat0x00441C20,40byteslong.Data:CC0014300160000000000000000000000Objectdumpcomplete.根据这段输出信息,你无法知道在哪个源程序文件里发生了内存泄漏。下面我们来研究一下输出信息的格式。第一行和第二行没有什么可说的,从第三行开始:xx}:花括弧内的数字是内存分配序号,本文例子中是{45},{44},{43};block:内存块的类型,常用的有三种:normal(普通)、client(客户端)或CRT(运行时);本文例子中是:normalblock;用十六进制格式表示的内存位置,如:at0x00441BA0等;以字节为单位表示的内存块的大小,如:32byteslong;前16字节的内容(也是用十六进制格式表示),如:Data:AB4142等;仔细观察不难发现,如果定义了_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,即普通块和客户端块。normalblock(普通块):这是由你的程序分配的内存。clientblock(客户块):这是一种特殊类型的内存块,专门用于MFC程序中需要析构函数的对象。MFCnew操作符视具体情况既可以为所创建的对象建立普通块,也可以为之建立客户块。CRTblock(CRT块):是由CRunTimeLibrary供自己使用而分配的内存块。由CRT库自己来管理这些内存的分配与释放,我们一般不会在内存泄漏报告中发现CRT内存泄漏,除非程序发生了严重的错误(例如CRT库崩溃)。除了上述的类型外,还有下面这两种类型的内存块,它们不会出现在内存泄漏报告中:freeblock(空闲块):已经被释放(free)的内存块。Ignoreblock(忽略块):这是程序员显式声明过不要在内存泄漏报告中出现的内存块。如何在内存分配序号处设置断点?在内存泄漏报告中,的文件名和行号可告诉分配泄漏的内存的代码位置,但仅仅依赖这些信息来了解完整的泄漏原因是不够的。因为一个程序在运行时,一段分配内存的代码可能会被调用很多次,只要有一次调用后没有释放内存就会导致内存泄漏。为了确定是哪些内存没有被释放,不仅要知道泄漏的内存是在哪里分配的,还要知道泄漏产生的条件。这时内存分配序号就显得特别有用——这个序号就是文件名和行号之后的花括弧里的那个数字。例如,在本文例子代码的输出信息中,“45”是内存分配序号,意思是泄漏的内存是你程序中分配的第四十五个内存块:Detectedmemoryleaks!Dumpingobjects-C:/Temp/memleak/memleak.
本文标题:VC++ 6.0 中如何使用 CRT 调试功能来检测内存泄漏
链接地址:https://www.777doc.com/doc-3968658 .html