说明
- 之前公司,C项目中为了程序检测内存泄漏问题,采用一个自己实现的库,能够记录内存分配和释放操作,程序结束或者通过信号可以生成dump信息来分析内存问题。
技术分析
- 内存分配和释放记录主要是通过hook(钩子)技术来获取的。
hook技术
通过预处理实现
- 创建一个头文件,通过宏替换的方式替换掉内存分配(malloc,calloc,realloc)和释放函数(free)。
- 创建一个源文件,定义替换函数,在替换函数中记录调用和调用真正的目标函数和做相应处理。
* 头文件 MemHook.h
#if defined(__cplusplus)
extern "C" {
#endif
#define malloc(size) mmalloc(size , __FILE__, __LINE__)
#define calloc(size) mcalloc(size, __FILE__, __LINE__)
.....
#define free(p) mfree(p)
#if defined(__cplusplus)
}
#endif
* 源码
#include <stdio.h>
#include <stdlib.h>
//不能引入 MemHook.h
void *mmalloc (unsigned long counts, const char* const file , const unsigned long line)
{
void *buf;
printf("%s , %ld\n", file , line);
if (NULL == (buf = malloc(counts)))
{
....
return NULL;
}
//记录内存分配
....
return buf;
}
.....
void mfree (void *p)
{
if (p)
{
//记录内存释放
.....
free(p);
}
}
- 需要手动引入该头文件,如果有源码未引入该头文件,会导致操作未记录。
LD_PRELOAD 环境变量方式
- 方式简介:
- LD_PRELOAD 是在所有动态库前加载该环境变量定义的动态库。
- 方式说明:
- 实现一个动态库,通过LD_PRELOAD环境变量,在所有动态库前加载。
- 动态库中定义标准的内存分配和释放函数,例如:malloc,calloc,free等;由于先加载,变量设置后运行的程序中调用的这些函数都会被指向该库中的实现。
- 在该库中记录分配和释放记录,以及调用真正的malloc,calloc,free等函数。
* 库源码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
static void *(*true_malloc)(size_t);
static void (*true_free)(void *ptr);
void *malloc(size_t size)
{
void *ptr;
if (true_malloc == NULL)
{
true_malloc = dlsym(RTLD_NEXT, "malloc");
}
printf(%d\n", size);
ptr = true_malloc(size);
//记录分配操作
....
return ptr;
}
.....
void free(void* ptr)
{
if (true_free == NULL)
{
true_free = dlsym(RTLD_NEXT, "free");
}
//记录释放操作
....
printf("%p\n", ptr);
return true_free(ptr);
}
* 注意:
1. 函数定义需要和标准的一样。
2. 生成动态库时需要链接 dl库。
* 编译生成动态库
* 设置环境变量
export LD_PRELOAD=./libxxxx.so
* 执行其它程序
- 替换方式简单,环境变量设置和取消非常方便。