参考链接 里面的示例代码
typedef struct DATA_{
DATA_(int size = 10){
pVoid = new char[nSize];
this->size = size;
}
virtual ~DATA_() {
if (pVoid){
delete pVoid;
}
}
int nSize;
void *pVoid;
}DATA, *LPDATA;
struct STRUCT1{
STRUCT1(int count){
pVoid = new DATA[count];
this->count = count;
}
virtual ~STRUCT1(){
if (pVoid){
delete pVoid;
}
}
int count;
union {
void *pVoid;
LPDATA pData;
}
}
int main(int argc, char* argv[]){
for( int i = 0; i < 1000; i++){
void *p = new STRUCT1( 10 );
delete p;
}
return 0;
}
造成内存泄漏的原因 在上面这段代码中,STRUCT1中包含了若干个DATA结构,DATA结构又申请了默认为10byte大小的内存,并且内存在对象析构的时候会用delete回收。乍一看这个代码貌似不会泄露内存,其实不然,待我分析:
在C++中构造函数与析构函数的调用是由编译器完成的,其中构造函数的调用一般是在对象空间开辟完以后(栈对象或者堆对象都是一样的),将参数压栈,this指针(对象的起始地址)放入eax寄存器(不同的编译器做法可能不同),然后跳到构造函数去执行。而析构函数的调用则是当对象内存被回收的时候被调用(栈对象是当代码执行到变量可见域外之前调用, 堆对象是在delete语句的位置进行调用)。
然而编译器并是那么智能的可以理解coder的意图,析构函数的调用是根据当前delete的指针类型来确定的,而(下面)这段代码却没有提供类型, 这导致了DATA_的析构函数将不会被调用,内存泄漏就在所难免了。
避免出现内存泄漏的注意事项:
-
始终结合使用 memset 和 malloc分配内存,或始终使用 calloc。 -
每当向指针写入值时,都要确保对可用字节数和所写入的字节数进行交叉核对。 -
在对指针赋值前,要确保没有内存位置会变为孤立的。 -
每当释放结构化的元素(而该元素又包含指向动态分配的内存位置的指针)时,都应首先遍历子内存位置并从那里开始释放,然后再遍历回父节点。 -
始终正确处理返回动态分配的内存引用的函数返回值。 -
每个 malloc 都要有一个对应的 free。 -
确保您不是在访问空指针。 那么存在空指针会出现内存泄漏吗,是不会的,因为空指针本身就没有给他分配内存空间,充其量只是在栈上占用了四个字节的变量空间,一旦脱离域之后自然消失了。 像如下面这个例子
#include<bits/stdc++.h>
using namespace std;
struct A{
int b;
A(){
cout<<"rrrrrrrrrr"<<endl;
}
~A(){
cout<<"dddd"<<endl;
}
};
struct B{
A* p;
~B(){
cout<<"ooooooooo"<<endl;
delete p;
cout<<"mmmmmmmmm"<<endl;
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
B *e;
delete e;
return 0;
}
A里面的b都没有初始化,压根就是个空指针,delete空指针不会产生任何操作,而且空指针本身也不会申请得到空间,但是会出错。 运行结果如下:
|