使用C/C++语言开发的软件在运行时,出现内存泄漏。可以使用以下两种方式,进行检查排除。
⑴ 使用工具软件BoundsChecker,BoundsChecker是一个运行时错误检测工具,它主要定位程序运行时期发生的各种错误。它通过驻留在集成开发环境内部的自动处理调试程序来加速应用程序的开发,缩短产品发布时间。BoundsChecker对于编程中的错误(大多数是C++中特有的)提供了清晰的详细的分析。它能够检测和诊断出,在静态堆栈内存中的错误以及内存和资源泄漏问题。在集成开发环境下,调试运行DEBUG版程序,BoundsChecker在运行时检测内存泄漏,并在可能出现内存泄漏的代码处中断程序运行,开发人员可根据调用现场状态,排除内存泄漏。
⑵ 调试运行DEBUG版程序,运用以下技术:CRT(C run-time libraries)、运行时函数调用堆栈、内存泄漏时提示的内存分配序号(集成开发环境OUTPUT窗口),综合分析内存泄漏的原因,排除内存泄漏。
首先,需要在程序中包含以下语句,用来启用调试堆函数(注:语句的顺序是固定的)
#define CRTDBG_MAP_ALLOC
#include
#include
其次,设置内存泄漏检测报告。使用以下语句,在程序结束后,自动调用_CrtDumpMemoryLeaks方法,在OUTPUT窗口中报告内存泄漏的相关信息
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
最后,根据OUTPUT窗口中提示的内存泄漏相关信息,排除泄漏。分两种情况。
情况一、比较简单。程序退出时,在OUTPUT窗口中,直接报告:出现内存泄漏的源代码文件名及具体代码行数。只需要分析此处代码,根据上、下文修改,一般就可以正确释放内存了。例如:
Detected memory leaks!
Dumping objects ->
C: \MyProjects\LeakTest\LeakTest.cpp(20): {18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
C: \MyProjects\LeakTest\LeakTest.cpp(20)
情况二、比较麻烦。错误报告没有映射到源文件。可使用_CrtSetBreakAlloc方法来检查定位内存泄漏位置。
例如:
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
注意到报告中的一个信息:{18}。大括号中的这个整数值代表了内存分配顺序号。这个例子中,{18}代表了第18次内存分配操作发生了泄漏。在程序运行时,_CrtSetBreakAlloc方法可以在指定的内存分配次数时中断程序。使用这种方式获得的信息,比在程序退出时获得文件名及行号更有价值。因为报告内存泄漏文件名及行号,获得的只是静态信息,而_CrtSetBreakAlloc则是把整个现场恢复,可以通过对函数调用栈的分析、以及使用其他在线调试技巧,来分析产生内存泄漏的原因。_CrtSetBreakAlloc要求你的程序执行过程是可还原的(即:多次执行过程的内存分配顺序不会发生变化),这个假设在多数情况下成立。不过,在多线程的情况下,这个要求有时难以保证。但是虽然内存分配顺序号是变化的,但是变化的顺序号却总是那几个,也就是说,对某个位置的内存泄漏,多运行几次程序,内存分配的顺序号很可能会重复。所以,多线程环境下,也可以使用_CrtSetBreakAlloc方法来定位内存泄漏。具体操作步骤如下:
①先在调试状态下运行几次程序,观察内存分配顺序号是哪几个值。
②用出现次数最多的那个顺序号来设断点。即:在代码中添加如下调用:_CrtSetBreakAlloc(18);(假设: OUTPUT窗口中,报告{18}最多。即:第18次内存分配出现泄漏的情况较常发生)
③在调试状态下运行程序,在断点停下时,打开"调用堆栈"窗口,找到对应发生内存泄漏的源代码。
④退出程序,观察OUTPUT窗口的内存泄漏报告,看本次内存分配的顺序号是不是和预设值(_CrtSetBreakAlloc中设置的值)相同,如果相同,就找到了;如果不同,就重复步骤3,直到相同。
⑤最后根据分析结果,在适当的位置释放分配的内存。