内存泄露的含义是:拿走了一块“堆”内存块,在某检查点处,发现没有归还这个内存块。 如果是: 地址A = malloc(N); 因为没有调用free(地址A),所以内存泄露了。

如果是: 地址B = new 类型T; 因为没有调用delete 地址B,所以内存泄露了。

如果是:从用户的内存池中取一个内存块,没有调用相应的归还给内存池的操作,也认为是“内存泄露”。

从哪里拿了一个东西,要归还到那个地方去。例如:从图书馆L中借了本书,归还给图书馆B,肯定要挨骂的。

同理,从图书馆L中借了本小说,却还给图书馆一本杂志,也是要挨骂的。 函数_CrtDumpMemoryLeaks()功能:检查内存泄露并且在VC的输出窗口打印出泄露的内存块信息。

例子1 :

#include

#include

 

int main()

{ int* x = new int();

_CrtDumpMemoryLeaks()

}

输出:

Detected memory leaks!

Dumping objects -> {61} normal block at 0x00382650, 4 bytes long. Data: < > 00 00 00 00

非常好,发现了int* x对应的内存块泄露了

 

例子2 :

template struct Test

{ Test()

{m_p = new char[Size];

}

~Test()

{ delete[] m_p;}

char* m_p;

};

Test<123> t;

int main()

{ int* x = new int()

; _CrtDumpMemoryLeaks() ;

}

输出:

Detected memory leaks!

{62} normal block at 0x00382708, 4 bytes long.

{61} normal block at 0x00382650, 123 bytes long.

非常不好,它把全局变量t也报告了。这是一个严重的误报。

原因是在_CrtDumpMemoryLeaks()调用时, 全局变量t还没有离开生存期呢,所以此时~Test()未调用呢,delete[] m_p还没调用呢。

 

例子3 :

Test<123> t;

int main()

{ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

int* x = new int();

}

输出:

Detected memory leaks!

{62} normal block at 0x00382708, 4 bytes long.

非常好,通过_CrtSetDbgFlag函数,告知Crt库在程序完全退出时,打印一下内存泄露的情况。

这时,全局变量t已经析构了,所以误报没有了。

 

例子4 :

#include

using namespace std;

#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)

#define new DEBUG_NEW

int main()

{ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

int* x = new int();

}

输出:

Detected memory leaks!

c:/sdfdfsdf/sdfdfsdf.cpp(14) :

{61} normal block at 0x00382650, 4 bytes long.

太酷了!居然在调试的输出窗口中,显示了造成内存泄露的代码位置。

双击一下,还能自动跳到文本编辑器 中对应的代码行上。

 

例子5 :

#include int main()

{ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

std::cout<<"hello world"<

 

调用堆栈窗口。 看到一些函数的调用关系,顺着点点看看,居然发现了int* x = new int;这一行。

这个62是怎么知道的呢?原来在内存泄露的输出信息里,

如下所示:

Detected memory leaks!

{62} normal block at 0x00382708, 4 bytes long.

大括号中62就是第62次分配内存时,这块内存泄露了。通过_CrtSetBreakAlloc调用,告知Crt库,在 第62次分配内存的调用时,

自动暂停程序,让程序员检查函数调用栈。 如何保证下次程序运行时,

第62此分配内存的调用就是int* x = new int;这句造成的呢?

答案是不能。

如果程序没有复杂的时序相关的逻辑(多线程),输入的值是一定的,则程序每次运行的行为是一定的。

 

例子8 :

class Init_before_main

{

public: Init_before_main()

{ _CrtSetBreakAlloc(62);

}

};

Init_before_main g_tmp;

int main()

{ int* x = new int;

return 0;

}

这是对例子7的一点改进,保证在int* x = new int;调用之前,调_CrtSetBreakAlloc(62);。

否则,如下的调用顺序可能会漏过了第62次分配调用 int* x = new int; _CrtSetBreakAlloc(62);

如何自己实现内存泄露检查工具呢?思路很简单,重载new,delete运算符,使用自己宏替换malloc和free。

所有的分配和释放动作必须经过我过手,我才能加入点私货(统计信息等)。这样就可以检查内存泄露了。