内存泄漏一直是编程中不易察觉但可能会造成严重后果的大问题。在c/c++这种没有垃圾回收的语言系统中尤其明显。最近编程中遇到了一些相关的问题,网上没有查到满意的结果,特此整理收集。
PS:关于堆内存和栈内存的区别这里就不赘述了,网上有很多,理解起来也很容易
异常处理时的内存释放
先写结论:抛出异常时,栈内存会自动释放,而堆内存不会——这点与普通的函数退出一样。
按照网上的一些说法(虽然是关于线程的,但都有相似的问题),栈内存是在程序执行return语句时,编译器才会相应的释放该函数内新建的对象。所以之前一直怀疑,程序如果运行到抛出异常的节点而退出,(因为没有执行return)是否就无法顺利释放相应内存。于是写了下面一段代码测试:
class myclass{
int a;
public:
myclass(int a):a(a){};
int getNum(){ return a;};
~myclass(){
a=0;
cout<<"destruction fun"<<endl;
};
};
void test(myclass *&p){
myclass m(7);
p=&m;
throw exception();
p->getNum();
}
int main(int argc,char** argv){
myclass* p;
try{
test(p);
}
catch (exception) {
cout<<p->getNum()<<endl;
}
return 0;
}
程序运行的结果是
destruction fun
0
可以发现,虽然子函数抛出异常回到主函数中了,但子函数仍然执行了myclass
的析构函数。值得注意的是,通过p
指针仍能访问这个理应被析构了的对象m
并得到正确的结果。但这并不说明m
没有被析构,只是原先记录m
数据的内存还没有被新数据刷新覆盖而已。
如果我们调整一下test
函数如下,尝试把新对象建立在堆内存上:
void test(myclass *&p){
p=new myclass(7);
throw exception();
p->getNum();
}
其他程序不变,最后的结果则变成了
7
可以发现,析构函数没有被调用(想想也不太可能对吧),这里就会造成内存泄漏了。
–待续