以下是一个用C语言实现的内存泄漏检测工具的示例代码。该工具通过LD_PRELOAD机制拦截内存管理函数,并检测目标程序的内存泄漏情况。
// leak_checker.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <pthread.h>
#define BACKTRACE_SIZE 16
typedef struct _alloc_info {
void *ptr;
size_t size;
void *stack[BACKTRACE_SIZE];
int stack_size;
struct _alloc_info *next;
} alloc_info;
static alloc_info *alloc_list = NULL;
static pthread_mutex_t alloc_mutex = PTHREAD_MUTEX_INITIALIZER;
static void *(*real_malloc)(size_t) = NULL;
static void (*real_free)(void *) = NULL;
static void *(*real_calloc)(size_t, size_t) = NULL;
static void *(*real_realloc)(void *, size_t) = NULL;
__attribute__((constructor)) void init() {
real_malloc = dlsym(RTLD_NEXT, "malloc");
real_free = dlsym(RTLD_NEXT, "free");
real_calloc = dlsym(RTLD_NEXT, "calloc");
real_realloc = dlsym(RTLD_NEXT, "realloc");
atexit(report_leaks);
}
void *malloc(size_t size) {
void *ptr = real_malloc(size);
if (ptr) {
alloc_info *info = real_malloc(sizeof(alloc_info));
info->ptr = ptr;
info->size = size;
info->stack_size = backtrace(info->stack, BACKTRACE_SIZE);
pthread_mutex_lock(&alloc_mutex);
info->next = alloc_list;
alloc_list = info;
pthread_mutex_unlock(&alloc_mutex);
}
return ptr;
}
void free(void *ptr) {
if (ptr) {
pthread_mutex_lock(&alloc_mutex);
alloc_info **p = &alloc_list;
while (*p) {
if ((*p)->ptr == ptr) {
alloc_info *found = *p;
*p = found->next;
real_free(found);
break;
}
p = &(*p)->next;
}
pthread_mutex_unlock(&alloc_mutex);
real_free(ptr);
}
}
void *calloc(size_t nmemb, size_t size) {
void *ptr = real_calloc(nmemb, size);
if (ptr) {
alloc_info *info = real_malloc(sizeof(alloc_info));
info->ptr = ptr;
info->size = nmemb * size;
info->stack_size = backtrace(info->stack, BACKTRACE_SIZE);
pthread_mutex_lock(&alloc_mutex);
info->next = alloc_list;
alloc_list = info;
pthread_mutex_unlock(&alloc_mutex);
}
return ptr;
}
void *realloc(void *ptr, size_t size) {
if (ptr == NULL) {
return malloc(size);
}
void *new_ptr = real_realloc(ptr, size);
if (new_ptr) {
pthread_mutex_lock(&alloc_mutex);
alloc_info **p = &alloc_list;
while (*p) {
if ((*p)->ptr == ptr) {
alloc_info *found = *p;
*p = found->next;
real_free(found);
break;
}
p = &(*p)->next;
}
pthread_mutex_unlock(&alloc_mutex);
alloc_info *info = real_malloc(sizeof(alloc_info));
info->ptr = new_ptr;
info->size = size;
info->stack_size = backtrace(info->stack, BACKTRACE_SIZE);
pthread_mutex_lock(&alloc_mutex);
info->next = alloc_list;
alloc_list = info;
pthread_mutex_unlock(&alloc_mutex);
}
return new_ptr;
}
void report_leaks() {
pthread_mutex_lock(&alloc_mutex);
alloc_info *current = alloc_list;
if (current) {
fprintf(stderr, "\n=== Memory leak detected ===\n");
while (current) {
fprintf(stderr, "Leaked %zu bytes at %p\n", current->size, current->ptr);
char **symbols = backtrace_symbols(current->stack, current->stack_size);
if (symbols) {
for (int i = 0; i < current->stack_size; i++) {
fprintf(stderr, "%s\n", symbols[i]);
}
real_free(symbols);
}
alloc_info *next = current->next;
real_free(current);
current = next;
}
fprintf(stderr, "============================\n");
}
pthread_mutex_unlock(&alloc_mutex);
}
编译和使用说明:
-
编译共享库:
使用以下命令将上述代码编译为共享库:
gcc -shared -fPIC -o leak_checker.so leak_checker.c -ldl -lpthread
-
测试程序示例:
创建一个有内存泄漏的测试程序
test.c
:// test.c #include <stdlib.h> int main() { malloc(100); // 未释放的内存 return 0; }
编译测试程序:
gcc test.c -o test -g -rdynamic
-g
选项生成调试信息,-rdynamic
选项确保能正确解析函数名。 -
运行检测:
使用
LD_PRELOAD
加载共享库运行测试程序:LD_PRELOAD=./leak_checker.so ./test
程序运行结束后,会输出内存泄漏信息,包括泄漏的内存大小和调用堆栈。
注意事项:
-
该工具适用于Linux环境,并依赖
glibc
。 -
需要目标程序动态链接C库(大部分程序默认如此)。
-
目标程序编译时应包含调试信息(
-g
)和符号导出(-rdynamic
),以便正确显示堆栈信息。 -
该工具会拦截所有内存操作,可能对程序性能有一定影响。
这个实现通过拦截内存管理函数来跟踪内存分配和释放,程序退出时报告未释放的内存块及其调用堆栈,帮助开发者定位内存泄漏问题。