目录
前言
一、内存泄漏基本概念
二、如何判断并查找内存泄漏
1、方案设计
2、方案实现
前言
对于C/C++程序员来说,或多或少都会被面试官问到关于内存泄漏的问题,内存泄漏是程序的bug,他会一点一点的侵蚀你的内存,导致程序运行一段时间后会莫名崩溃,本文就主要讲解如何不使用工具来查找内存泄漏的问题;
一、内存泄漏基本概念
所谓内存泄漏,一般是调用了类似malloc、realloc 等在堆空间申请内存的函数,当我们在使用完以后未释放申请的空间便会导致内存泄漏,下面是一段经典的内存泄漏代码;
我们尝试对如下代码编译链接并执行,如下图所示;
我们发现与正常程序执行并无差别,也没有报错相关信息,我们无法的得知是否有内存泄漏相关问题,于是我们有了如下想法;
二、如何判断并查找内存泄漏
1、方案设计
关于内存泄漏程序,我们并没有能力能看出是否内存泄漏,如上述程序,我们得设计一个方案,首先能排查出这个程序是否有内存泄漏,其次我们也要找到内存泄漏的位置;这样才是一个合格的方案;
思路:我们对malloc函数 “重写” ,在申请内存前,首先申请空间,然后再创建一个文件,文件内容是在何处调用这个malloc函数,接着我们也对 free 函数完成 “重写” ,我们在free函数删除这个文件;在程序运行结束后,我们可以通过是否还有我们因malloc创建的文件判断是否发生了内存泄漏的问题;
2、方案实现
下面就是方案实现代码;代码的核心在main函数上面的代码,这段代码仅仅作用于单文件的内存泄漏的查找;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
// 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 函数;