Linux C/C++服务器
内存泄漏检测组件
调用malloc或者new,没有调用free或delete
内存泄漏检测组件
- 如何判断是否有内存泄漏
- 到底在哪行代码泄漏
本文介绍三种内存泄漏检测的方法
- mtrace
- 宏定义
- hook malloc
mtrace
mtrace是系统自带的内存检测接口,引入mcheck.h头文件就可使用,使用也比较简单
#include <stdlib.h> #include <stdio.h> #include <mcheck.h> int main() { mtrace(); void *p1 = malloc(10); void *p2 = malloc(15); void *p3 = malloc(20); free(p2); free(p3); muntrace(); }
执行过程
gcc -o memleak memleak.c -g export MALLOC_TRACE=./mem.txt ./memleak cat mem.txt addr2line -f -e memleak -a 0x400ad0
低版本可行,在高版本中不会生成mem.txt文件
宏定义
只适合在单文件内,把它放在文件的最前面
为什么main函数中的malloc调用的是宏定义,而void _malloc()内调用的却不是宏定义?
预编译:1.把代码的注释取消 2.宏定义展开,把宏定义直接搬过来,所以在打印行号的时候不会出问题
编译:把各个字符转代码文件换成各个二进制文件
链接:把各个文件的代码模块组装起来
#include <stdlib.h> #include <stdio.h> #include <unistd.h> void *_malloc(size_t size, const char *filename, int line) { void *p = malloc(size); char buff[128] = {0}; sprintf(buff, "./mem/%p.mem", p); FILE *fp = fopen(buff, "w"); fprintf(fp, "[+]%s:%d, addr: %p, size: %ld\n", filename, line, p, size); fflush(fp); fclose(fp); //printf("[+]%s:%d, %p\n", filename, line, p); return p; } void _free(void *p, const char *filename, int line) { //printf("[-]%s:%d, %p\n", filename, line, p); char buff[128] = {0}; sprintf(buff, "./mem/%p.mem", p); if (unlink(buff) < 0) { //删除文件 printf("double free: %p\n", p); return ; } return free(p); } #define malloc(size) _malloc(size, __FILE__, __LINE__) #define free(size) _free(size, __FILE__, __LINE__) int main() { void *p1 = malloc(10); //_malloc(size, __FILE__, __LINE__) void *p2 = malloc(15); void *p3 = malloc(20); free(p2); free(p3); return 0; }
执行过程
gcc -o memleak memleak.c -g mkdir mem ./memleak
hook
hook接口在调试追踪代码中使用的较多,主要是通过dlsym()和typedef函数指针类型来实现,在之前死锁检测组件中我们也有使用和详细说明
#define _GNU_SOURCE #include <dlfcn.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> typedef void *(*malloc_t)(size_t size); typedef void (*free_t)(void *ptr); malloc_t malloc_f = NULL; free_t free_f = NULL; int enable_malloc_hook = 1; void *malloc(size_t size) { void *p = NULL; if(enable_malloc_hook){ enable_malloc_hook = 0; //printf内部也会调用malloc,如果不加enable_malloc_hook标志位终止条件,将导致递归出现段错误 //printf("size: %ld\n", size); p = malloc(size); void *caller = __builtin_return_address(0); //可返回是哪里调用的本函数 char buff[128] = {0}; sprintf(buff, "./mem/%p.mem", p); FILE *fp = fopen(buff, "w"); fprintf(fp, "[+]%p, addr: %p, size: %ld\n", caller, p, size); fflush(fp); fclose(fp); enable_malloc_hook = 1; }else{ p = malloc(size); } return p; } void free(void *ptr) { if(enable_malloc_hook){ enable_malloc_hook = 0; //printf("ptr: %p\n", ptr); char buff[128] = {0}; sprintf(buff, "./mem/%p.mem", ptr); if (unlink(buff) < 0) { printf("double free: %p\n", ptr); return ; } free_f(ptr); enable_malloc_hook = 1; } } static void init_hook(void) { if (malloc_f == NULL) { malloc_f = (malloc_t)dlsym(RTLD_NEXT, "malloc"); } if (free_f == NULL) { free_f = (free_t)dlsym(RTLD_NEXT, "free"); } } int main() { init_hook(); //3.hook void *p1 = malloc(10); void *p2 = malloc(15); void *p3 = malloc(20); free(p2); free(p3); return 0; }
执行过程
gcc -o memleak memleak.c -g -ldl mkdir mem ./memleak cat mem/0x55818bb172a0.mem addr2line -f -e memleak -a 0x1651
以上只是给出了检测内存泄漏的方法,但实际工程中检测内存泄漏要复杂的多,而且并不能100%的检测出来
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构