Linux C / C++ 编程检查内存泄露的方法

C / C++中的内存泄露一般指堆中的内存泄露。堆内存是我们手动malloc/realloc/new申请的,程序不会自动回收,需要调用free或delete手动释放,否则就会造成内存泄露。内存泄露其实还应该包括系统资料的泄露,比如socket连接等,使用完后也要释放。

内存泄露的原因:

总结下来,内存泄露大概有一下几个原因:

  1. 编码错误:malloc、realloc、new申请的内存在堆上,需要手动显示释放,调用free或delete。申请和释放必须成对出现malloc/realloc对应free,new对应delete。前者不会运行构造/析构函数,后者会。对于C++内置数据类型可能没差别,但是对于自己构造的类,可能在析构函数中释放系统资源或释放内存,所以要对应使用。
  2. “无主”内存:申请内存后,指针指向内存的起始地址,若丢失或修改这个指针,那么申请的内存将丢失且没有释放。
  3. 异常分支导致资源未释放:程序正常执行没有问题,但是如果遇到异常,正常执行的顺序或分支会被打断,得不到执行。所以在异常处理的代码中,要确保系统资源的释放。
  4. 隐式内存泄露:程序运行中不断申请内存,但是直到程序结束才释放。有些服务器会申请大量内存作为缓存,或申请大量Socket资源作为连接池,这些资源一直占用直到程序退出。服务器运行起来一般持续几个月,不及时释放可能会导致内存耗尽。
  5. 类的析构函数为非虚函数:析构函数为虚函数,利用多态来调用指针指向对象的析构函数,而不是基类的析构函数。

内存泄露的检测

内存泄露的关键就是记录分配的内存和释放内存的操作,看看能不能匹配。跟踪每一块内存的生命周期,例如:每当申请一块内存后,把指向它的指针写入到日志( 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日志文件

log日志文件

log日志文件

您可能还喜欢...

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据