【工作总结】内存泄漏总结
这篇博文写了放在草稿箱很久一直没整理好,现在刚好又碰到内存泄露,所以花一下午时间整理一下发表出来。
一、内存泄漏高发地带
1、new/delete或malloc/free不成对。
2、从函数return的一段内存。
char* GetMem(int size) { char *p = new char[size]; return p; } char *p = GetMem(); strcpy(p, "hahahaha\0"); //此处容易忘记delete p;
3、init后忘记release,这是一般在使用第三方库时候,申请了资源,在使用完忘记释放。
4、往容器中比如vector、list、map中插入了一段内存,在使用完未进行释放。
vector<char*> vec; char *p = new char[16]; memset(p, 0, 16); vec.push_back(p); //在vec.pop以后忘记delete p
5、catch,在程序执行过程中产生了异常,直接进入catch,如果处理不当,可能会产生内存泄露。
void TestCatch() { try { char *p = new char[16]; doSomething(); //如果doSomething出现异常,直接进入catch,p没有被delete delete p; p = NULL; } catch (exception e) { } }
6、虚析构函数,在多态中,一定要将基类的析构函数设置为virtual。如果在析构函数中有内存释放的操作,且基类的析构函数没有设置为vitual的情况下,可能会发生内存泄露。
class Person { public: Person() { m_pName = new char[20]; } virtual ~Person() { delete m_pName; m_pName = NULL; } private: char *m_pName; }; class Coder : public Person { public: Coder(){} ~Coder(){} void doCode() { cout << "code" << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { Person *p = NULL; p = new Coder(); p->doCode(); return 0; } //在上面的代码中,如果Person的析构函数不是virtual,p则不会调用Person的析构函数,m_pName也不会被释放。
8、线程退出,在多线程中,线程退出时忘记释放内存也是造成内存泄露高频发生地段。
9、拷贝构造函数。拷贝构造构造函数的返回值和传入值一定要是引用类型,否则会栈溢出。原因是当一个对象以传递值的方式传一个函数的时候,拷贝构造函数自动的调用来生 成函数中的对象.这样会导致无限循环地调用拷贝构造函数,直至栈溢出
二、如何预防内存泄露
1、养成良好的编码习惯,new/delete或malloc/free或第三方库申请和释放资源的接口成对出现。
2、使用内存池。
3、使用智能指针。
4、使用自定义内存管理类。
三、检测内存泄露
1、手动检测
如果代码文件比较少,即可通过代码搜索工具全工程搜索出malloc、new关键字,然后找到相应的free或delete。
2、Valgrind
点击下载,最新版本是3.9.0。
使用方法可以参考官方文档,点这里。
安装就是常规的./configure && make &&make install。
安装完成以后就可以使用valgrind来检测程序是否存在内存问题。可以参考这篇博文。