一、内存泄漏(memory leak)

内存泄漏(memory leak)是指由于疏忽或错误造成了程序未能释放掉不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。也就是我们常说的 堆内存的泄漏。

堆内存泄漏(Heap leak)。对内存指的是程序运行中根据需要分配通过malloc,realloc new等从堆中分配的一块内存,再是完成后必须通过调用对应的 free或者delete 删掉。如果程序的设计的错误导致这部分内存没有被释放,那么此后这块内存将不会被使用,就会产生Heap Leak.

二、内存泄漏的后果?

只发生一次小的内存泄漏可能不被注意,但泄漏大量内存的程序将会出现各种征兆;性能下降到内存逐渐用完,导致另一个程序失败,从而使用户无从查问题的真正根源。

三、内存泄漏的原因汇总:

1) 正确的使用new和delete运算符,需要注意的是new和delete要匹配使用,对于初学者这种情况是最常出现的。一般出错的地方像如下的例子,在指针p的值被另一个函数所使用。

char * FunA() {
	char *p = new char;
	return p;
}
void FunErrorB() {
	char *b = FunA();
			//忘记delete p
}

2) 释放对象数组时,没有使用delete[]。如例子所示:

Void FunErrorA(){
	char *p = new char[10];
	delete p;
}

3) 双指针释放错误,存在指针释放的遗漏。如例子正确的释放一个双指针

void FunRightA() {
	char **p = new char*[10];
	For(int i=0;
	i<10;
	i++) {
		p[i] = new char[10];
	}
	If(p!=nullptr) {
		For(int i=0;
		i<10;
		i++) {
			delete []p[i];
			p[i] = nullptr;
		}
		delete []p;
		p = nullptr;
	}
}

4) 缺少拷贝构造函数。在类里存在成员变量是指针时,在进行赋值=运算和按值传参时,必须重载拷贝构造函数,重新实现其指针拷贝的部分.

5) 没有将基类的析构函数定义为虚函数。当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用,子类的资源没有正确是释放,因此造成内存泄露。

6) 调用库存在内存泄漏。在使用由个人包装或者未完全测试的库时,要确定此库对本程序不存在性能的影响。


c++提供了auto_ptr、unique_ptr、shared_ptr和weak_ptr这几种智能指针(auto_ptr是C++98提供的解决方案,C+11已将将其摒弃,并提供了另外两种解决方案。)在此我们只介绍后三个智能指针:

(1)shared_ptr共享的智能指针:

shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。在最后一个shared_ptr析构的时候,内存才会被释放。

注意事项:
1.不要用一个原始指针初始化多个shared_ptr。
2.不要再函数实参中创建shared_ptr,在调用函数之前先定义以及初始化它。
3.不要将this指针作为shared_ptr返回出来。
4.要避免循环引用。

(2)unique_ptr独占的智能指针:

<1>Unique_ptr是一个独占的智能指针,他不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另外一个 unique_ptr。

<2>unique_ptr不允许复制,但可以通过函数返回给其他的unique_ptr,还可以通过std::move来转移到其他的unique_ptr,这样它本身就不再 拥有原来指针的所有权了。

<3>如果希望只有一个智能指针管理资源或管理数组就用unique_ptr,如果希望多个智能指针管理同一个资源就用shared_ptr。

(3)weak_ptr弱引用的智能指针:

弱引用的智能指针weak_ptr是用来监视shared_ptr的,不会使引用计数加一,它不管理shared_ptr内部的指针,主要是为了监视shared_ptr的生命 周期,更像是shared_ptr的一个助手。 weak_ptr没有重载运算符*和->,因为它不共享指针,不能操作资源,主要是为了通过shared_ptr获得资源的监测权,它的构造不会增加引用计数,它的析构不会减少引用计数,纯粹只是作为一个旁观者来监视shared_ptr中关连的资源是否存在。 weak_ptr还可以用来返回this指针和解决循环引用的问题。

四、检测工具

Linux :可以使用 Valgrind(–tool = memcheck)

Windows 下检测内存泄漏的工具常用的一般有三种,MS C-Runtime Library内建的检测功能;外挂式的检测工具,诸如,Purify,BoundsChecker等;利用Windows NT自带的Performance Monitor。这三种工具各有优缺点,MS C-Runtime Library虽然功能上较之外挂式的工具要弱,但是它是免费的;Performance Monitor虽然无法标示出发生问题的代码,但是它能检测出隐式的内存泄漏的存在,这是其他两类工具无能为力的地方。