梁越

内存溢出、内存泄露、野指针、空指针

0 人看过

彻底理清内存溢出,内存泄露,野指针和空指针

内存溢出

看到下面代码的情况,如果使用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;
}

内存泄露

内存泄露往往是对指针操作不当出现的,没有正确回收

  1. new和delete,malloc和free没有成对的出现,也就是没有正确回收
{
    int *p = new int[100];
    delete p;//new[],delete []不匹配,导致99对象的内存空间被泄漏。 
    delete []p; //这里正确使用
}
  1. 调用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;
}
  1. 没有将子类的析构函数设置为虚函数,导致某些情况,例如使用子类实例化基类对象时,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!

野指针和空指针

野指针的情况

  1. 指针没有初始化为某个对象或者nullptr或者NULL

  2. 指针被delete后没有置空,也就是设置NULL或者nullptr

char *p = (char *)malloc(10);
strcpy(p,"hello");
free(p);  //p所指的内存被释放,变为垃圾内存(不可用内存),但是p所指的地址没变。
//p=NULL 应该加上这样一句
if(p != NULL)  //没有起到防错作用
strcpy(p,"world");  //篡改动态内存区,后果难以预料,非常危险
  1. 指针超过了作用域返回,导致指针不知道指向了谁

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情况,指针被回收了,其实对象是空的