内存泄漏:内存泄漏是由于内存分配与内存释放不匹配所引起的。
- 手写内存泄漏检测组件
方法一:使用mtrace,但需要重启程序
思路:设置环境变量 export MALLOC_TRACE=“xxx/mem.txt”, xxx表示你希望存放的路径,然后在程序的开头加上mtrace(),在末尾加上muntrace()
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <mcheck.h>
int main() {
mtrace();
int *p1 = (int*)malloc(5);
int *p2 = (int*)malloc(15);
free(p1);
muntrace();
return 0;
}
编译时需要加上-g选项
mem.txt中的内容为:
= Start
@ ./a.out:[0x5555555551c4] + 0x555555559690 0x5
@ ./a.out:[0x5555555551d2] + 0x5555555596b0 0xf
@ ./a.out:[0x5555555551e2] - 0x555555559690
= End
使用addr2line -f -e a.out -a xxx
, xxx为怀疑内存泄漏的地址,使用该命令可以找到是程序中的哪个函数的哪一行发生了内存泄漏。
但是0x5555555551c4,为虚拟内存中的地址,无法使用addr2line,所以需要在程序中使用dladdr1函数将将地址转换为.elf中的符号信息。
使用完后将环境变量设置回来 export MALLOC_TRACE=""
具体实现:https://zhuanlan.zhihu.com/p/554448993
总的来说方案一的实现觉复杂,笔者推荐方案二。
方案二:宏定义
方案一还需要自己找出内存泄漏的地址,而使用宏定义即可跳过这一步。
思路:
● 使用宏定义,调用malloc后,以返回的指针指向的地址创建文件,并写入其在代码中的多少行等相关信息;
● 在调用free之前,使用unlink函数删除目录项,并且减少一个链接数。
● 执行完后,剩下的那个文件名即为内存泄漏的地址。
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define ENABLE_MEM 1
void * _malloc(size_t sz, const char * file, int line) {
void * p = malloc(sz);
char buff[256] = {0};
sprintf(buff, "%p.mem", p);
FILE* fp = fopen(buff, "w"); // 以返回的指针指向的地址创建文件
// 填写相关信息
fprintf(fp, "+[%s:%d] addr:%p, size: %lu byte(s)\n", file, line, p, sz);
fflush(fp);
fclose(fp);
return p;
}
void _free(void * ptr) {
char buff[256] = {0};
sprintf(buff, "%p.mem", ptr);
if (unlink(buff) < 0) {
printf("Doule free: %p\n", ptr);
return ;
}
free(ptr);
}
#if ENABLE_MEM
#define malloc(size) _malloc(size, __FILE__, __LINE__)
#define free(p) _free(p);
#endif
int main() {
int *p1 = (int*)malloc(5);
int *p2 = (int*)malloc(15);
free(p1);
return 0;
}