内存溢出、内存泄露、野指针、空指针
彻底理清内存溢出,内存泄露,野指针和空指针
内存溢出
看到下面代码的情况,如果使用while循环一直调用GetMemory,一直malloc内存,但是没有使用free函数释放内存,会导致最后没有空间分配,产生的这种情况就是内存溢出
#include <stdlib.h>
#include <iostream>
using namespace std;
void GetMemory(char *p, int num)
{
p = (char*)malloc(sizeof(char) * num);//使用new也能够检测出来
}
int main(int argc,char** argv)
{
char *str = NULL;
GetMemory(str, 100);
cout<<"Memory leak test!"<<endl;
//如果main中存在while循环调用GetMemory
//那么问题将变得很严重
//while(1){GetMemory(...);}
return 0;
}
内存泄露
内存泄露往往是对指针操作不当出现的,没有正确回收
- new和delete,malloc和free没有成对的出现,也就是没有正确回收
{
int *p = new int[100];
delete p;//new[],delete []不匹配,导致99对象的内存空间被泄漏。
delete []p; //这里正确使用
}
- 调用void *类型的对象,导致没有调用对象的析构函数,内存没有回收
class Object {
private:
void* data;
const int size;
const char id;
public:
Object(int sz, char c):size(sz), id(c){
data = new char[size];
cout << "Object() " << id << " size = " << size << endl;
}
~Object(){
cout << "~Object() " << id << endl;
delete []data;
}
};
int main() {
Object* a = new Object(10, 'A');//Object*指针指向一个Object对象;
void* b = new Object(20, 'B');//void*指针指向一个Object对象;
delete a;//执行delete,编译器自动调用析构函数;
delete b;//执行delete,编译器不会调用析构函数,导致data占用内存没有得到回收;
return 0;
}
- 没有将子类的析构函数设置为虚函数,导致某些情况,例如使用子类实例化基类对象时,delete基类只会调用基类的析构函数,具体可以看这里
#include <iostream>
using namespace std;
class Father
{
public:
Father() { cout << "contructor Father!" << endl; };
~Father() { cout << "destructor Father!" << endl; };
};
class Son :public Father
{
public:
Son() { cout << "contructor Son!" << endl; };
~Son() { cout << "destructor Son!" << endl; }; //需要设置为析构函数
};
int main()
{
Father *pfather=new Son;
delete pfather;
pfather = NULL;
return 0;
}
//ontructor Father!
//contructor Son!
//destructor Father!
野指针和空指针
野指针的情况
指针没有初始化为某个对象或者nullptr或者NULL
指针被delete后没有置空,也就是设置NULL或者nullptr
char *p = (char *)malloc(10);
strcpy(p,"hello");
free(p); //p所指的内存被释放,变为垃圾内存(不可用内存),但是p所指的地址没变。
//p=NULL 应该加上这样一句
if(p != NULL) //没有起到防错作用
strcpy(p,"world"); //篡改动态内存区,后果难以预料,非常危险
- 指针超过了作用域返回,导致指针不知道指向了谁
class A
{
public:
void Func(void){ cout << “Func of class A” << endl; }
};
void Test(void)
{
A *p;
{
A a;
p = &a; // 注意 a 的生命期,过了{}即被回收
}
p->Func(); // p是“野指针”
空指针一般就是指针没有初始化为某个对象,导致使用的时候异常,或者类似野指针中的3情况,指针被回收了,其实对象是空的