VC++内存泄漏的检测(下)
实际的应用程序并不是这样简单,调用者之间的关系也是错综复杂,所以这更加需要高明的内存检测方案。比如我们的测试代码中有一个
类 my_test_class,这个类非常简单,但是有多个位置在使用这个类,代码如下所示:
class my_test_class
{
public:my_test_class(){data = new char[10];}virtual ~my_test_class(){delete[]data;}
private:char* data;
};
代码中的 my_test_class 类本身并没有问题,也不会有泄漏情况发生。但是如果使用这个类的位置发生内存泄漏,也会导致这个类本身的
内存泄漏,而且最后会被检测到。
测试代码如下:
#include <iostream>
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define malloc(s) _malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__)
#endifclass my_test_class
{
public:my_test_class(){data = new char[10];}virtual ~my_test_class(){delete[]data;}
private:char* data;
};void my_test_new()
{int* test1 = new int[100];int* test2 = new int[16];memset(test2, 0, 16);
}void my_test_malloc()
{my_test_class* test = new my_test_class();char* test1 = (char*)malloc(100);char* test2 = (char*)malloc(6);
}int main()
{//启用调试对管理_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF);std::cout << "Memory leak test" << std::endl;my_test_new();my_test_malloc();_CrtDumpMemoryLeaks(); //显示内存泄漏报告return 0;
}
我们看到有两处test c的内存泄漏,位置都指向代码的第11行,即 my_test_class 的构造函数。但是我们无法在 my_test_class 的构造函
数中设置断点来查看调用的位置,因为有很多地方会调用 my_test_class 类,而且大部分调用是正常的。所以,我们需要使用其他方法,
使代码能够在发生内存泄漏时暂停,以便能够观察当时的运行环境,包括栈情况等。
前面介绍过,在输出窗口显示的内存泄漏报告中,除文件名和行号外,还有一个内存分配的序号。序号168对应的内存分配就是
my_test_class 构造函数中的 new 分配内存。所以我们希望在这次分配内存时,代码能够发生中断。
在 VC 运行时,库调试函数中还有一个函数,可以用来设置断点。函数原型如下:
_CrtSetBreakAlloc(_In_ long _NewValue );
该函数只有一个参数,就是内存分配的序号。即当内存分配到该序号时,代码就会发生中断。在代码中使用该函数,因为我们希望在第
168 次分配内存时发生中断,所以将 168作为参数传递,再重新按 F5 键执行代码,这时就会在第 168 次分配内存时发生中断.
而且我们可以很轻松地通过堆栈看到,main 函数中调用了 my_test_malloc 函数,my_test_malloc 函数中分配了 my_test_class,最后导致内存泄漏。
该文章会更新,欢迎大家批评指正。
推荐一个零声学院免费公开课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:
服务器课程:C++服务器