目录
对于C/C++程序员来说,或多或少都会被面试官问到关于内存泄漏的问题,内存泄漏是程序的bug,他会一点一点的侵蚀你的内存,导致程序运行一段时间后会莫名崩溃,本文就主要讲解如何不使用工具来查找内存泄漏的问题;
所谓内存泄漏,一般是调用了类似malloc、realloc 等在堆空间申请内存的函数,当我们在使用完以后未释放申请的空间便会导致内存泄漏,下面是一段经典的内存泄漏代码;
我们尝试对如下代码编译链接并执行,如下图所示;
我们发现与正常程序执行并无差别,也没有报错相关信息,我们无法的得知是否有内存泄漏相关问题,于是我们有了如下想法;
关于内存泄漏程序,我们并没有能力能看出是否内存泄漏,如上述程序,我们得设计一个方案,首先能排查出这个程序是否有内存泄漏,其次我们也要找到内存泄漏的位置;这样才是一个合格的方案;
思路:我们对malloc函数 “重写” ,在申请内存前,首先申请空间,然后再创建一个文件,文件内容是在何处调用这个malloc函数,接着我们也对 free 函数完成 “重写” ,我们在free函数删除这个文件;在程序运行结束后,我们可以通过是否还有我们因malloc创建的文件判断是否发生了内存泄漏的问题;
下面就是方案实现代码;代码的核心在main函数上面的代码,这段代码仅仅作用于单文件的内存泄漏的查找;
- #include
- #include
- #include
- #include
-
- // malloc 函数重写
- // 第一个参数为申请大小,第二个参数为文件名,第三个参数为行号
- void* _malloc(size_t size, const char* file, int line)
- {
- // 文件内容
- char buf[128] = { 0 };
- // 文件名
- char filename[128] = "./memfile/"; // 当前目录的memfile目录保存所有文件
- char tmp[128] = { 0 };
- // 调用malloc申请内存
- void* p = malloc(size);
- // 生成对应内容
- sprintf(buf, "memLeak-%p-%s-%d", p, file, line);
- sprintf(tmp, "%p", p);
- strcat(filename, tmp);
- // 打开文件
- FILE* pf = fopen(filename, "w");
- // 写入操作
- fwrite(buf, 1, strlen(buf), pf);
- // 关闭文件
- fclose(pf);
- pf = NULL;
-
- return p;
- }
- // free 函数重写
- void _free(void* p)
- {
- char buf[128] = "./memfile/";
- char tmp[128] = { 0 };
- sprintf(tmp, "%p", p);
- strcat(buf, tmp);
- if(unlink(buf) < 0) // unlink函数为删除文件的函数
- {
- // 这个文件被free了两次
- printf("free 重复调用");
- return ;
- }
- free(p);
- }
-
- // 这里的宏定义切记不可写在上面的重写函数之上,不然会循环调用
- #define malloc(N) _malloc(N, __FILE__, __LINE__)
- #define free(p) _free(p)
-
- int main()
- {
- void* p1 = malloc(10);
- void* p2 = malloc(20);
-
- free(p1);
- return 0;
- }
我们运行上述代码,确实发现了memfile目录下有一个文件;如下所示;
我们打开这个文件,查看内容;
在memeryLeak.c文件下的54行确实就是没有释放的 malloc 函数;