首页 > 代码库 > C++内存泄露和检测

C++内存泄露和检测

C++中的内存泄露一般指堆中的内存泄露。堆内存是我们手动malloc/realloc/new申请的,程序不会自动回收,需要调用free或delete手动释放,否则就会造成内存泄露。内存泄露其实还应该包括系统资料的泄露,比如socket连接等,使用完后也要释放。

内存泄露的原因:

总结下来,内存泄露大概有一下几个原因:

1、编码错误:malloc、realloc、new申请的内存在堆上,需要手动显示释放,调用free或delete。申请和释放必须成对出现malloc/realloc对应free,new对应delete。前者不会运行构造/析构函数,后者会。对于C++内置数据类型可能没差别,但是对于自己构造的类,可能在析构函数中释放系统资源或释放内存,所以要对应使用。

2、“无主”内存:申请内存后,指针指向内存的起始地址,若丢失或修改这个指针,那么申请的内存将丢失且没有释放。

3、异常分支导致资源未释放:程序正常执行没有问题,但是如果遇到异常,正常执行的顺序或分支会被打断,得不到执行。所以在异常处理的代码中,要确保系统资源的释放。

4、隐式内存泄露:程序运行中不断申请内存,但是直到程序结束才释放。有些服务器会申请大量内存作为缓存,或申请大量Socket资源作为连接池,这些资源一直占用直到程序退出。服务器运行起来一般持续几个月,不及时释放可能会导致内存耗尽。

5、类的析构函数为非虚函数:析构函数为虚函数,利用多态来调用指针指向对象的析构函数,而不是基类的析构函数。


内存泄露的检测

内存泄露的关键就是记录分配的内存和释放内存的操作,看看能不能匹配。跟踪每一块内存的声明周期,例如:每当申请一块内存后,把指向它的指针加入到List中,当释放时,再把对应的指针从List中删除,到程序最后检查List就可以知道有没有内存泄露了。Window平台下的Visual Studio调试器和C运行时(CRT)就是用这个原理来检测内存泄露。

在VS中使用时,需加上

#define _CRTDBG_MAP_ALLOC

#include <crtdbg.h>

crtdbg.h的作用是将malloc和free函数映射到它们的调试版本_malloc_dbg和_free_dbg,这两个函数将跟踪内存分配和释放(在Debug版本中有效)

_CrtDumpMemoryLeaks();

函数将显示当前内存泄露,也就是说程序运行到此行代码时的内存泄露,所有未销毁的对象都会报出内存泄露,因此要让这个函数尽量放到最后。

例如:

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#include <iostream>
using namespace std;
int main(int argc,char** argv)
{
	char *str1 = NULL;
	char *str2 = NULL;
	str1=new char[100];
	str2=new char[50];

	delete str1;
	_CrtDumpMemoryLeaks();
	return 0;
}

上述代码中,内存申请了两块,但是只释放了一块,运行调试,会在output窗口输出:

Dumping objects ->
{136} normal block at 0x00084D70, 50 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
Object dump complete.

可以看到会检测到内存泄露。

也可以用此法更复杂检测内存泄露,例如设置检查点,检查检查点之间的内存泄露。

在Linux下也有类似的方法,具体可以参考:http://en.wikipedia.org/wiki/Mtrace

C++内存泄露和检测