内存泄露:为申请了堆内存,但没有释放,即未还给操作系统。长此以往,系统的可分配内存越来越少,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
在 Linux下进行 C/C++ 开发,常常会动态分配一些堆内存。那就可能会存在"内存泄露"的问题。
如果 Linux下做 C/C++ 开发时,出现内存泄漏了,我们该如何去定位呢?
常用的定位工具:mtrace 工具 与 valgrind工具 ,这两个都是典型的内存泄漏分析工具。
在我们的调用内存分配和释放的函数中装载 “钩子(hook)” 函数,通过 “钩子” 函数打印的 log 日志,对日志文件的分析来帮助我们分析对内存的使用是否存在问题。
对该工具的使用包括两部分内容:一个是要修改源码,装载 hook 函数。另一个是通过运行修改后的程序,生成特殊的 log 文件。然后利用 mtrace工具分析日志,判断是否存在内存泄露以及定位可能发生内存泄露的代码位置。
接下来用一段代码说明一下, mtrace 工具如何定位 "内存泄露" 。在使用之前,需要修改我们的源码,用来跟踪内存分配和释放,其中需要使用两个函数:
#include
void mtrace(void); //开启内存分配跟踪
void muntrace(void); //关闭内存分配跟踪
将上述函数接口加入待检测的代码中,代码如下:
#include
#include
#include
int main(int argc, char **argv)
{
setenv("MALLOC_TRACE", "memery_leak.log", 1);
mtrace();
char *p1 = (char*)malloc(16);
char* p2 = (char*)malloc(20);
free(p1);
p1 = NULL;
muntrace();
return 0;
}
编译代码,终端输入命令:gcc -g main.c -o main.out
运行程序,终端输入:./main.out 命令。当前目录下就会生成 memory_leak.log 文件。
定位问题,终端输入:mtrace main.out memory_leak.log 命令后,并没有定位到 C 源码的具体行数,如下所示:
下面使用 地址转化工具 addr2line 工具分析一下,上面地址是对应到哪一行 C 代码行。如下所示:
可以看出,能够猜到可能是后面的地址不对。导致 addr2line 工具转换失败。
网上百度到,可能的原因如下:
1. 关闭 Linux 系统的 ASLR 功能。
ASLR 功能全称为 Address Space Layout Randomization,地址空间布局随机化。它将进程的某些内存空间地址进行随机化来增大入侵者预测目的地址的难度,从而降低进程被成功入侵的风险。
2. 编译源码时,加上 "-no-pie" 选项。
下来进行具体的操作,操作如下:
(1)关闭 ASLR 功能:
输入命令:cat /proc/sys/kernel/randomize_va_space ,查看 Linux 系统的 ASLR 值是 2,说明默认 ASLR 功能是开启的。
设置 ASLR 的值:输入命令 : echo 0 > /proc/sys/kernel/randomize_va_space
(2)加入 "-no-pie" 选项后重新编译程序。输入命令: gcc -g -no-pie main.c -o main.out
(3)然后运行程序,终端输入命令: ./main.out
(4)使用 mtrace 工具查看 新生成的 memory_leak.log 文件。
如下所示:
可以看到,定位到了 C 代码中的具体行。到此,mtrace 工具定位到 C 代码的具体的 11 行代码存在内存泄露 。