内存泄漏的原因通常是进行了malloc(或类似操作)又没有进行free。
检测内存泄漏需要关注:1、判断是否有内存泄漏。2、内存泄漏发生在哪一行。
宏定义方法制造组件
该方法仅适用于单文件检测内泄漏,因为宏定义只在当前文件中有效。
这里的组件指的是利用宏定义功能将内存操作相关的函数(malloc,free等)在保留原有功能的基础上增添上所需功能的函数。
如何判断是否有内存泄漏?
该组件可以在每次程序malloc的时候根据内存地址生成一个内存相关文件,每次程序free的时候根据内存地址销毁相关文件。最后如果有剩余文件,说明有内存泄漏
如何判断泄漏发生在哪一行?
用__LINE__和__FILE__宏定位发生内存操作的具体代码位置。
如何设置组件开关?
通过设置flag决定是否开启检测组件。
代码:
Hook方法制造组件
Hook方法制造组件除了单文件,也适合检测多文件、第三方库等是否存在内存泄漏,以及非第三方库造成的内存泄漏在哪一行等。
Hook在编程中是一种技术,这种技术简单来说就是让函数(也能是类、事件等)在保留原有功能的基础上,拓展功能。相比起宏,函数功能的拓展可以不仅仅在当前文件中,也能在其他文件中。
在本案例用dlsym实现hook,过程如下:
1、定义能容纳原函数的函数类型并构造相关变量。
2、将原函数存储在相关变量中。
3、重新实现与原函数同名的函数,在其中调用相关的函数变量,以此保留原函数的功能,并增加功能。
重点细节:
- 有些第三方库的函数(比如printf、getchar),会在底层的代码中调用malloc,为了防止循环调用形成阻塞,需要设置变量和if引导第三方的库的函数调用malloc的时候走的是重定义之前的malloc。
- Gcc编译的要加-g选项,-g是给编译的可执行文件添加调试信息(变量名、文件名、行号、类型信息等),方便我们在终端利用addr2line定位发生内存泄漏的行号。
__builtin_return_address
函数,会返回函数的地址。参数为0表示当前函数的调用地址。参数为1表示当前函数的调用的那一行所在的函数的地址。一般填0。
- 高版本的linux用addr2line识别行号, 传入的地址用自定义的函数ConvertToEL产生,是一个相对地址,相对代码载入内存中的起始地址。如果是低版本的linux则不需要调用该函数、
代码:
执行结果: