ImageVerifierCode 换一换
格式:DOCX , 页数:34 ,大小:243.47KB ,
资源ID:5209586      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/5209586.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(CRT 调试功能来检测内存泄漏.docx)为本站会员(b****3)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

CRT 调试功能来检测内存泄漏.docx

1、CRT 调试功能来检测内存泄漏VC+ 6.0 中如何使用 CRT 调试功能来检测内存泄漏作者:JerryZ下载例子源代码最近看了周星星 Blog 中的一篇文章:“VC+6.0中内存泄漏检测”,受益匪浅,便运行其例子代码想看看 Output 窗口中的输出结果,可惜怎么弄其输出都不是预期的东西,郁闷了半天,便到水坛里找到周星星,请求他指点一、二,然而未果。没有办法,最后我一头栽进 MSDN 库狂搜了一把,功夫不负有心人,我搜出很多有关这方面的资料,没过多久我便基本上就找到了答案.首先,检测内存泄漏的基本工具是调试器和 CRT 调试堆函数。为了使用调试堆函数,必须在要检测内存泄漏和调试的程序中添加下

2、面的语句: #define _CRTDBG_MAP_ALLOC #include #include #include debug_new.hMSDN 如是说:“必须保证上面声明的顺序,如果改变了顺序,可能不能正常工作。”至于这是为什么,我们不得而知。MS 的老大们经常这样故弄玄虚。针对非 MFC 程序,再加上周星星的头文件:debug_new.h,当然如果不加这一句,也能检测出内存泄漏,但是你无法确定在哪个源程序文件中发生泄漏。Output 输出只告诉你在 crtsdb.h 中的某个地方有内存泄漏。我测试时 REG_DEBUG_NEW 没有起作用。加不加这个宏都可以检测出发生内存分配泄漏的文件

3、。其次,一旦添加了上面的声明,你就可以通过在程序中加入下面的代码来报告内存泄漏信息了:_CrtDumpMemoryLeaks();这就这么简单。我在周星星的例子代码中加入这些机关后,在 VC+ 调试会话(按 F5 调试运行) Output 窗口的 Debug 页便看到了预期的内存泄漏 dump。该 dump 形式如下: Detected memory leaks! Dumping objects - c:/Program Files/./include/crtdbg.h(552) : 45 normal block at 0x00441BA0, 2 bytes long. Data: 41 4

4、2 c:/Program Files/./include/crtdbg.h(552) : 44 normal block at 0x00441BD0, 33 bytes long. Data: 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD c:/Program Files/./include/crtdbg.h(552) : 43 normal block at 0x00441C20, 40 bytes long. Data: E8 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00 Object dump

5、complete.更具体的细节请参考本文附带的源代码文件。下面是我看过 MSDN 资料后,针对“如何使用 CRT 调试功能来检测内存泄漏?”的问题进行了一番编译和整理,希望对大家有用。如果你的英文很棒,那就不用往下看了,建议直接去读 MSDN 库中的技术原文。C/C+ 编程语言的最强大功能之一便是其动态分配和释放内存,但是中国有句古话:“最大的长处也可能成为最大的弱点”,那么 C/C+ 应用程序正好印证了这句话。在 C/C+ 应用程序开发过程中,动态分配的内存处理不当是最常见的问题。其中,最难捉摸也最难检测的错误之一就是内存泄漏,即未能正确释放以前分配的内存的错误。偶尔发生的少量内存泄漏可能不

6、会引起我们的注意,但泄漏大量内存的程序或泄漏日益增多的程序可能会表现出各种 各样的征兆:从性能不良(并且逐渐降低)到内存完全耗尽。更糟的是,泄漏的程序可能会用掉太多内存,导致另外一个程序垮掉,而使用户无从查找问题的真正根源。此外,即使无害的内存泄漏也可能殃及池鱼。幸运的是,Visual Studio 调试器和 C 运行时 (CRT) 库为我们提供了检测和识别内存泄漏的有效方法。下面请和我一起分享收获如何使用 CRT 调试功能来检测内存泄漏?1. 如何启用内存泄漏检测机制? o 使用 _CrtSetDbgFlag o 设置 CRT 报告模式 2. 解释内存块类型 3. 如何在内存分配序号处设置断

7、点? 4. 如何比较内存状态? 5. 结论 如何启用内存泄漏检测机制?VC+ IDE 的默认状态是没有启用内存泄漏检测机制的,也就是说即使某段代码有内存泄漏,调试会话的 Output 窗口的 Debug 页不会输出有关内存泄漏信息。你必须设定两个最基本的机关来启用内存泄漏检测机制。一是使用调试堆函数:#define _CRTDBG_MAP_ALLOC #include #include注意:#include 语句的顺序。如果更改此顺序,所使用的函数可能无法正确工作。通过包含 crtdbg.h 头文件,可以将 malloc 和 free 函数映射到其“调试”版本 _malloc_dbg 和 _f

8、ree_dbg,这些函数会跟踪内存分配和释放。此映射只在调试(Debug)版本(也就是要定义 _DEBUG)中有效。发行版本(Release)使用普通的 malloc 和 free 函数。#define 语句将 CRT 堆函数的基础版本映射到对应的“调试”版本。该语句不是必须的,但如果没有该语句,那么有关内存泄漏的信息会不全。二是在需要检测内存泄漏的地方添加下面这条语句来输出内存泄漏信息:_CrtDumpMemoryLeaks();当在调试器下运行程序时,_CrtDumpMemoryLeaks 将在 Output 窗口的 Debug 页中显示内存泄漏信息。比如: Detected memory

9、 leaks! Dumping objects - C:/Temp/memleak/memleak.cpp(15) : 45 normal block at 0x00441BA0, 2 bytes long. Data: 41 42 c:/program files/microsoft visual studio/vc98/include/crtdbg.h(552) : 44 normal block at 0x00441BD0, 33 bytes long. Data: 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD c:/program fi

10、les/microsoft visual studio/vc98/include/crtdbg.h(552) : 43 normal block at 0x00441C20, 40 bytes long. Data: 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 b

11、ytes long. Data: 41 42 44 normal block at 0x00441BD0, 33 bytes long. Data: 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: C0 01 43 00 16 00 00 00 00 00 00 00 00 00 00 00 Object dump complete.根据这段输出信息,你无法知道在哪个源程序文件里发生了内存泄漏。下面我们来研究一下输出信息的格式。第一行和第二行没

12、有什么可说的,从第三行开始: xx:花括弧内的数字是内存分配序号,本文例子中是 45,44,43; block:内存块的类型,常用的有三种:normal(普通)、client(客户端)或 CRT(运行时);本文例子中是:normal block; 用十六进制格式表示的内存位置,如:at 0x00441BA0 等; 以字节为单位表示的内存块的大小,如:32 bytes long; 前 16 字节的内容(也是用十六进制格式表示),如:Data: 41 42 等;仔细观察不难发现,如果定义了 _CRTDBG_MAP_ALLOC ,那么在内存分配序号前面还会显示在其中分配泄漏内存的文件名,以及文件名后

13、括号中的数字表示发生泄漏的代码行号,比如: C:/Temp/memleak/memleak.cpp(15)双击 Output 窗口中此文件名所在的输出行,便可跳到源程序文件分配该内存的代码行(也可以选中该行,然后按 F4,效果一样) ,这样一来我们就很容易定位内存泄漏是在哪里发生的了,因此,_CRTDBG_MAP_ALLOC 的作用显而易见。使用 _CrtSetDbgFlag如果程序只有一个出口,那么调用 _CrtDumpMemoryLeaks 的位置是很容易选择的。但是,如果程序可能会在多个地方退出该怎么办呢?在每一个可能的出口处调用 _CrtDumpMemoryLeaks 肯定是不可取的,

14、那么这时可以在程序开始处包含下面的调用: _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );这条语句无论程序在什么地方退出都会自动调用 _CrtDumpMemoryLeaks。注意:这里必须同时设置两个位域标志:_CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF。设置 CRT 报告模式默认情况下,_CrtDumpMemoryLeaks 将内存泄漏信息 dump 到 Output 窗口的 Debug 页, 如果你想将这个输出定向到别的地方,可以使用 _CrtSetReportMod

15、e 进行重置。如果你使用某个库,它可能将输出定向到另一位置。此时,只要使用以下语句将输出位置设回 Output 窗口即可:_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );有关使用 _CrtSetReportMode 的详细信息,请参考 MSDN 库关于 _CrtSetReportMode 的描述。解释内存块类型前面已经说过,内存泄漏报告中把每一块泄漏的内存分为 normal(普通块)、client(客户端块)和 CRT 块。事实上,需要留心和注意的也就是 normal 和 client,即普通块和客户端块。 normal block(普通

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

17、(free)的内存块。 Ignore block(忽略块):这是程序员显式声明过不要在内存泄漏报告中出现的内存块。 如何在内存分配序号处设置断点?在内存泄漏报告中,的文件名和行号可告诉分配泄漏的内存的代码位置,但仅仅依赖这些信息来了解完整的泄漏原因是不够的。因为一个程序在运行时,一段分配内存的代码可能会被调用很多次,只要有一次调用后没有释放内存就会导致内存泄漏。为了确定是哪些内存没有被释放,不仅要知道泄漏的内存是在哪里分配的,还要知道泄漏产生的条件。这时内存分配序号就显得特别有用这个序号就是文件名和行号之后的花括弧里的那个数字。例如,在本文例子代码的输出信息中,“45”是内存分配序号,意思是泄

18、漏的内存是你程序中分配的第四十五个内存块:Detected memory leaks! Dumping objects - C:/Temp/memleak/memleak.cpp(15) : 45 normal block at 0x00441BA0, 2 bytes long. Data: 41 42 . Object dump complete.CRT 库对程序运行期间分配的所有内存块进行计数,包括由 CRT 库自己分配的内存和其它库(如 MFC)分配的内存。因此,分配序号为 N 的对象即为程序中分配的第 N 个对象,但不一定是代码分配的第 N 个对象。(大多数情况下并非如此。)这样的话,

19、你便可以利用分配序号在分配内存的位置设置一个断点。方法是在程序起始附近设置一个位置断点。当程序在该点中断时,可以从 QuickWatch(快速监视)对话框或 Watch(监视)窗口设置一个内存分配断点:例如,在 Watch 窗口中,在 Name 栏键入下面的表达式:_crtBreakAlloc如果要使用 CRT 库的多线程 DLL 版本(/MD 选项),那么必须包含上下文操作符,像这样: ,msvcrtd.dll_crtBreakAlloc现在按下回车键,调试器将计算该值并把结果放入 Value 栏。如果没有在内存分配点设置任何断点,该值将为 1。用你想要在其位置中断的内存分配的分配序号替换

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

21、还可以使用有相同效果的 _CrtSetBreakAlloc 函数:_CrtSetBreakAlloc(45);如何比较内存状态?定位内存泄漏的另一个方法就是在关键点获取应用程序内存状态的快照。CRT 库提供了一个结构类型 _CrtMemState。你可以用它来存储内存状态的快照:_CrtMemState s1, s2, s3;若要获取给定点的内存状态快照,可以向 _CrtMemCheckpoint 函数传递一个 _CrtMemState 结构。该函数用当前内存状态的快照填充此结构:_CrtMemCheckpoint( &s1 );通过向 _CrtMemDumpStatistics 函数传递 _

22、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.若要确定某段代码中是

23、否发生了内存泄漏,可以通过获取该段代码之前和之后的内存状态快照,然后使用 _CrtMemDifference 比较这两个状态:_CrtMemCheckpoint( &s1 );/ 获取第一个内存状态快照 / 在这里进行内存分配 _CrtMemCheckpoint( &s2 );/ 获取第二个内存状态快照 / 比较两个内存快照的差异 if ( _CrtMemDifference( &s3, &s1, &s2) ) _CrtMemDumpStatistics( &s3 );/ dump 差异结果顾名思义,_CrtMemDifference 比较两个内存状态(前两个参数),生成这两个状态之间差异的结

24、果(第三个参数)。在程序的开始和结尾放置 _CrtMemCheckpoint 调用,并使用 _CrtMemDifference 比较结果,是检查内存泄漏的另一种方法。如果检测到泄漏,则可以使用 _CrtMemCheckpoint 调用通过二进制搜索技术来分割程序和定位泄漏。结论尽管 VC + 具有一套专门调试 MFC 应用程序的机制,但本文上述讨论的内存分配很简单,没有涉及到 MFC 对象,所以这些内容同样也适用于 MFC 程序。在 MSDN 库中可以找到很多有关 VC+ 调试方面的资料,如果你能善用 MSDN 库,相信用不了多少时间你就有可能成为调试高手。本人水平不高,谬误在所难免,请大家拍

25、砖,不要客气。顺祝大家圣诞快乐!JerryZ 于 2004 年平安夜,调试方法和技巧作者:非凡便于调试的代码风格:1. 不用全局变量 2. 所有变量都要初始化,成员变量在构造函数中初始化 3. 尽量使用const 4. 详尽的注释 VC+编译选项:1. 总是使用/W4警告级别 2. 在调试版本里总是使用/GZ编译选项,用来发现在Release版本中才有的错误 3. 没有警告的编译:保证在编译后没有任何警告,但是在消除警告前要进行仔细检查 调试方法:1、使用 Assert(原则:尽量简单)assert只在debug下生效,release下不会被编译。例子: char* strcpy(char*

26、dest,char* source) assert(source!=0); assert(dest!=0); char* returnstring = dest; while(*dest+ = *source+)!= /0) ; return returnstring; 2、防御性的编程例子: char* strcpy(char* dest,char* source) if(source = 0) assert(false); reutrn 0; if(dest = 0) assert(false); return 0; char* returnstring = dest; while(*de

27、st+ = *source+)!= /0) ; return returnstring; 3、使用Trace以下的例子只能在debug中显示,例子:a)、TRACECString csTest “test”; TRACE(“CString is s/n”,csTest);b)、ATLTRACEc)、afxDumpCTime time = CTime:GetCurrentTime(); #ifdef _DEBUG afxDump time “/n”; #endif4、用GetLastError来检测返回值,通过得到错误代码来分析错误原因5、把错误信息记录到文件中异常处理程序设计时一定要考虑到异常

28、如何处理,当错误发生后,不应简单的报告错误并退出程序,应当尽可能的想办法恢复到出错前的状态或者让程序从头开始运行,并且对于某些错误,应该能够容错,即允许错误的存在,但是程序还是能够正常完成任务。调试技巧1、VC+中F5进行调试运行a)、在output Debug窗口中可以看到用TRACE打印的信息b)、 Call Stack窗口中能看到程序的调用堆栈2、当Debug版本运行时发生崩溃,选择retry进行调试,通过看Call Stack分析出错的位置及原因3、使用映射文件调试a)、创建映射文件:Project settings中link项,选中Generate mapfile,输出程序代码地址:

29、/MAPINFO: LINES,得到引出序号:/MAPINFO: EXPORTS。b)、程序发布时,应该把所有模块的映射文件都存档。c)、查看映射文件:见” 通过崩溃地址找出源代码的出错行”文件。4、可以调试的Release版本Project settings中C+项的Debug Info选择为Program Database,Link项的Debug中选择Debug Info和Microsoft format。5、查看API的错误码,在watch窗口输入err可以查看或者err,hr,其中”,hr”表示错误码的说明。6、Set Next Statement:该功能可以直接跳转到指定的代码行执行

30、,一般用来测试异常处理的代码。7、调试内存变量的变化:当内存发生变化时停下来。常见错误1、在函数返回的时候程序崩溃的原因a)、写自动变量越界b)、函数原型不匹配2、MFCa)、使用错误的函数原型处理用户定义消息正确的函数原型为:afx_msg LRESULT OnMyMessage(WPARAM wParam,LPARAM lParam);3、谨慎使用TerminateThread:使用TerminateThread会造成资源泄漏,不到万不得已,不要使用。4、使用_beginthreadex,不要使用Create Thread来常见线程。参考资料:Windows程序调试功能强大的vc6调试器作者:yy2better要成为一位优秀的软件工程师,调试能力必不可缺。本文将较详细介绍VC6调试器的主要用法。 windows平台的调试器主要分为两大类: 1 用户模式(user-mode)调试器:它们都基于win32 Debugging API,有使用方便的界面,主要用于调试用户模式下的应用程序。这类调试器包括Visual C+调试器、WinDBG、BoundChecker、Borland C+ Builder调试器、NTSD等。 2 内核模式(kernel-mode)调试器:内核调试器位于CPU和操作系统之间,一旦启动,操作系统也会中止运行,主要用于调试驱动

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1