在 Linux 环境下进行 C/C++ 开发过程中,经常会使用 malloc/calloc() 函数分配堆空间,常常因为疏忽,忘记释放堆内存。从而导致内存泄露问题。
当发生肉眼可见大量的内存泄露时,可以使用 shell 命令来确认是否存在泄露。
但是,当每次程序只是发生几个字节的内存泄露时,shell 命令可能无法察觉到内存泄露问题。
这里介绍一种监测代码发生几个字节内存泄露的方法。
首先,在代码当前目录创建一个目录,存放调试log信息。
其次,自定义堆空间申请与释放的函数,即对堆空间申请/释放函数进行封装。在自定义的堆申请函数中,创建一个以堆地址命令的文件。
其次,在自定义的堆释放函数中,删除文件。
最后,将这部分监测代码用来测试代码中是否存在内存泄露。
注意: 这种方法只适用于单个 C/C++ 源文件,即对一个 C 文件中内存泄露问题的排查。
下面介绍具体的监测方法。在源码当前目录创建一个目录文件,下面创建了一个 debug目录。C 代码实现如下:
- #include
- #include
- #include
-
- #define FILE_CONTENTS "./debug"
-
- char file_name[256] = {0};
-
- void* check_malloc(size_t size, const char* file, int line)
- {
- void* p = malloc(size);
- sprintf(file_name, "%s/%p.mem", FILE_CONTENTS, p);
-
- FILE* fp = fopen(file_name, "w");
- fprintf(fp, "[+%s line: %d]--->addr: %p, size: %ld\n", file, line, p, size);
-
- fflush(fp);
- fclose(fp);
- return p;
- }
-
- void check_free(void* p, const char* file, int line)
- {
- sprintf(file_name, "%s/%p.mem", FILE_CONTENTS, p);
- if(unlink(file_name) < 0) //file no exist
- {
- printf("double free: %p\n", p);
- return;
- }
- free(p);
- }
-
- #define malloc(size) check_malloc(size, __FILE__, __LINE__)
- #define free(p) check_free(p, __FILE__, __LINE__)
-
- int main(void)
- {
- char* p1 = (char*)malloc(20);
- char* p2 = (char*)malloc(30);
- free(p2);
- p2 = NULL;
-
- return 0;
- }
使用上面代码即可对单个源码文件中代码进行内存泄露的排查。如下演示一下对下面一段代码的排查。
操作如下:
首先,在当前目录下,创建一个存放调试 log 信息的目录文件 debug。
其次,将第一段代码添加到待调试代码中。进行编译,即输入 gcc -g main.c -o main.out 命令。
最后,当存在内存泄露时会在 debug 文件中生成 相关文件。
如下所示:在 debug 目录下生成了 调试 Log 信息。可以看出,在代码 main.c 的 38 行出现了内存泄露问题。如下: