内存泄漏
概念
-
内存泄漏(memory leak),是指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。一般常说的内存泄漏是指堆内存的泄漏。
-
内存泄漏其实并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
-
内存泄漏与许多其他问题有着相似的症状,并且通常情况下只能由可以获得程序源代码的程序员才可以分析出来
-
应用程序一般使用malloc、calloc、realloc、new等函数从堆中分配到一块内存,使用完后,程序必须负责相应地调用free或delete释放该内存,否则这块内存就不能被再次使用,造成内存泄漏。频繁地使用malloc和free也会内存碎片(类似磁盘碎片)
如何避免内存泄漏
内存泄漏往往会导致系统出现内存资源耗尽的严重后果,所以开发人员在编码过程中要养成良好的编程习惯:
-
用malloc或new分配的内存都应当在适当的时机用free或delete释放
-
在对指针赋值前,要确保没有内存位置会变为孤立的。每当释放结构化的元素,而该元素又包含指向动态分配的内存位置的指针时,都应首先遍历子内存位置并从那里开始释放,然后再遍历回父结点
-
始终正确处理返回动态分配的内存引用的函数返回值
如何通过自定义函数的方法检测内存泄漏
第一种
一种简单的方法是,在申请内存的时候,把申请内存所在的文件名以及代码行号和申请出来的内存空间地址记录下来,当内存释放的时候,把记录下来的信息删除掉。当程序运行结束的时候,把没有释放的内存信息打印出来就可以知道代码中内存泄漏的地方了。
这种方法对于一个新开发的项目来说比较实用,但是对于一个已经存在很多年而且代码量非常大的项目来说却不是一个很好的方法。
第二种
另一种是通过拦截系统调用malloc/free来检测内存泄漏的方法。
通过自定义内存申请和释放方法mymalloc和myfree,然后设置一个钩子,让用户在调用malloc/free的时候会调用自定义的mymalloc/free函数,然后通过下面的宏定义实现当malloc被调用的时候就会默认调用mymalloc函数的功能。
#define malloc(size) mymalloc(size, __FILE__, __LINE__)
需要注意的是,在调用mymalloc的时候多传入了__FILE__和__LINE__两个参数,它们分别表示调用mymalloc的代码所在文件以及行号。有了这些信息后,主要的实现方法为:
自定义一个列表,每当malloc函数被调用的时候,mymalloc会被调用,mymalloc函数首先通过调用系统函数malloc把内存申请好,然后把调用者的信息(调用者所在文件和行号)以及申请好内存的信息添加到列表中;当myfree被调用的时候,首先通过调用系统函数free释放对应的内存,然后根据待释放的内存地址在列表中删除记录这块内存申请的信息。