Linux C / C++ 编程检查内存泄露的方法
C / C++中的内存泄露一般指堆中的内存泄露。堆内存是我们手动malloc/realloc/new申请的,程序不会自动回收,需要调用free或delete手动释放,否则就会造成内存泄露。内存泄露其实还应该包括系统资料的泄露,比如socket连接等,使用完后也要释放。
内存泄露的原因:
总结下来,内存泄露大概有一下几个原因:
- 编码错误:malloc、realloc、new申请的内存在堆上,需要手动显示释放,调用free或delete。申请和释放必须成对出现malloc/realloc对应free,new对应delete。前者不会运行构造/析构函数,后者会。对于C++内置数据类型可能没差别,但是对于自己构造的类,可能在析构函数中释放系统资源或释放内存,所以要对应使用。
- “无主”内存:申请内存后,指针指向内存的起始地址,若丢失或修改这个指针,那么申请的内存将丢失且没有释放。
- 异常分支导致资源未释放:程序正常执行没有问题,但是如果遇到异常,正常执行的顺序或分支会被打断,得不到执行。所以在异常处理的代码中,要确保系统资源的释放。
- 隐式内存泄露:程序运行中不断申请内存,但是直到程序结束才释放。有些服务器会申请大量内存作为缓存,或申请大量Socket资源作为连接池,这些资源一直占用直到程序退出。服务器运行起来一般持续几个月,不及时释放可能会导致内存耗尽。
- 类的析构函数为非虚函数:析构函数为虚函数,利用多态来调用指针指向对象的析构函数,而不是基类的析构函数。
内存泄露的检测
内存泄露的关键就是记录分配的内存和释放内存的操作,看看能不能匹配。跟踪每一块内存的生命周期,例如:每当申请一块内存后,把指向它的指针写入到日志( Log)文件中,当释放时,再把对应的指针从Log中做标记,到程序最后检查 Log 的标记是否匹配即可。下面是使用方法
首先在要检测内存泄露的 cpp 文件中包含 mcheck.h 头文件,然后在要检测内存泄露得地方调用 mtrace() 函数,在检测完毕得地方调用 muntrace() 函数(大多时间不用调用,因为有些会在muntrace之后才会被销毁),然后以Debug模式(-g)编译
之后打开控制台,设置保存的Log地址,如 export MALLOC_TRACE=a.log ,然后运行程序,等待其运行完毕,执行 mtrace a.out $MALLOC_TRACE 即可
例如下面得程序要检查内存泄露
int main(int argc, char **argv) { int a = 1; int *b = new int(2); int *c = new int(3); char *d = new char[100]; delete b; }
则修改后为
#include <mcheck.h> int main(int argc, char **argv) { mtrace(); int a = 1; int *b = new int(2); int *c = new int(3); char *d = new char[100]; delete b; }
下面是执行结果,可以看出,有2处内存泄露:
下面附上完整得log日志文件
1 条回复
[…] mtrace方法 Linux C / C++ 编程检查内存泄露的方法 – 悟能 […]