| 并且这些#include 语句必须按上边给出的顺序使用。如果你改变了顺序,可能导致使用的函数工作不正常。包含crtdbg.h的作用是用malloc和free函数的debug版本(_malloc_dbg 和 _free_dbg)来替换他们,他们能跟踪内存分配和回收。这个替换仅仅是在debug状态下生效,relese版本中还是使用普通的malloc和free函数。 上面的#define语句使用crt堆函数相应的debug版本来替换正常的堆函数。这个语句不是必需的,但是没有他,你可能会失去一些有用的内存泄漏信息。 你一旦在你的程序中增加了以上的语句,你可以通过在程序中增加_crtdumpmemoryleaks();函数来输出内存泄漏信息。
介绍一下内存块的类型: 就象前面指出的,一个内存泄漏信息指出每个内存泄漏块的类型为普通、客户端或者crt型。在实际程序中,普通型和客户端型式最常见的类型。 普通型内存块是你的程序平常分配的内存类型。 客户端型内存块是mfc程序给需要析构的对 象分配的内存块。mfc的new操作可以选择普通型或客户端型中合适的一种作为将要被创建的对象的内存块类型。 crt内存块是crt库为自己使用而分配的内存块。crt在处理自己的释放内存操作时使用这些块,所以在内存泄漏报告中这种类型并不常见,除非发生严重异常(例如:crt库出错)。 还有两种类型你在内存泄漏信息中看不到: 自由块,它是已经被释放的内存块; 忽略块,它是已经被特殊标示的内存块。 设置crt报告的格式: 在默认情况下,_crtdumpmemoryleaks输出的内存泄漏信息就象前边描述的那样。你可以使用_crtsetreportmode //其实是_CrtSetReportMode() 可见大小写都没对上 ,后面也是 我就不一一解释了 让这些输出信息输出到其他地方。如果你使用一个库,它可能要使输出信息到其他的地方,在这种情况下,你可以使用_crtsetreportmode( _crt_error, _crtdbg_mode_debug );语句使输出信息重新定位到output窗口。
根据内存分配编号设置断点: 内存泄漏报告中的文件名和行数告诉你内存泄漏的位置,但是知道内存泄漏位置不是总是能找到问题所在。在一个运行的程序中一个内存分配操作可能被调用多次,但是内存泄漏可能只发生在其中的某次操作中。为了确认问题所在,你除了知道泄漏的位置之外,你还必须要知道发生泄漏的条件。内存分配编号使得解决这个问题成为可能。这个数字就在文件名、行数之后的大括弧内。例如,在上面的输出中“18”就是内存分配编号,它的意思是你程序中的内存泄漏发生在第18次分配操作中。 crt库对正在运行程序中所有的内存块分配进行计数,包括自身的内存分配,或者其他库(象mfc)。一个对象的分配编号是n表示第n个对象被分配,但是它可能并不表示第n个对象通过代码被分配(在大多数情况下它们并不相同)。 你可以根据内存分配编号在内存被分配的位置设置断点。先在程序开始部分附近设置一个断点,当你的程序在断点处停止后,你可以通过quickwatch对话框或者watch窗口来设置内存分配断点。在watch窗口中的name列中输入_crtbreakalloc,如果你使用的是多线程dll版本的crt库的话你必须包含上下文转换 {,,msvcrtd.dll}_crtbreakalloc。完成后按回车,debugger处理这次调用,并且把返回值显示在value列中。如果你没有设置内存分配断点的话返回值是-1。在value列中输入你想设置的分配数,例如18。 你在自己感兴趣的内存分配位置设置断点后,你可以继续debugging。细心的运行你的程序在相同的条件下,这样才能保证内存分配的顺序不致发生变化。当程序在特定的内存分配处停下来后, 你可以查看call 窗口和其他的debugger信息来分析此次内存分配的条件。如果有必要你可以继续运行程序,看一看这个对象有什么变化,或许可以得知为什么内存没有被正确的释放。 尽管这个操作非常容易,但是如果你高兴的话也可以在代码中设置断点。在代码中增加一行代码_crtbreakalloc = 18;另外也可以通过_crtsetbreakalloc(18)来完成设置。 比较内存状态 另一个定位内存泄漏的方法是在重要位置捕捉应用程序的“内存快照”。crt库提供了一个结构体类型 _crtmemstate,使用它你可以保存内存状态的快照(当前状态)。 _crtmemstate s1, s2, s3; // _CrtMemState 为了得到一个快照,可以把一个_crtmemstate 结构体传给_crtmemcheckpoint 函数,这个函数可以把当前的内存状态填充在结构体中: _crtmemcheckpoint( &s1 ); 你可以通过把结构体_crtmemstate 传给_crtmemdumpstatistics函数来输出结构体中的内容。 _crtmemdumpstatistics( &s3 );( &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. 为了得知一段代码中是否有内存泄漏,你可以在这段代码的开始和完成处分别拍一个快照,然后调用_crtmemdifference函数来比较两个状态: _crtmemcheckpoint( &s1 ); // memory allocations take place here _crtmemcheckpoint( &s2 ); if ( _crtmemdifference( &s3, &s1, &s2) ) _crtmemdumpstatistics( &s3 ); 就像名字中暗示的那样,_crtmemdifference比较两个内存状态,并且产生一个结果(第一个参数)。把 _crtmemcheckpoint 放在程序的开始和结尾,调用_crtmemdifference 来比较结果,这也是一种检测内存泄漏的方法。如果发现内存泄漏,你可以使用_crtmemcheckpoint把程序分成两半分别使用上述方法来检测内存泄漏,这样就是使用二分法来检查内存泄漏。 |
相关文章: