程序中通常包含着静态内存和栈内存。静态内存用来保存局部static对象、类static数据成员以及定义在任何函数之外的变量(全局变量)。栈内存用来保存定义在函数内的非static对象。分配在静态或栈内存中的对象由编译器自动创建和销毁。对于栈对象,仅在定义的程序块运行时才存在,程序退出,栈对象也随即销毁;static对象和全局对象则是在程序结束时销毁。除了静态内存和栈内存,程序还拥有一块内存池,这部分也就是称为堆。在使用堆空间是就需要使用动态内存分配。
内存泄漏:是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
对于服务器程序及需要长时间运行的程序来说,检测和解决内存泄漏是程序员必备的技能。
1. 内存泄漏出现的情况总结
首先总结一下c++在语法上的错误使用导致的内存泄漏,所以在编写程序时,就尽量避免错误的编写。
(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)调用库存在内存泄漏。在使用由个人包装或者未完全测试的库时,要确定此库对本程序不存在性能的影响。
当遇到内存泄漏时,我们该如何进行确认出现内存泄露和定位内存泄露的位置。