使用valgrind进行内存泄漏检测

使用valgrind进行内存泄漏检测

内存泄漏是指程序中已动态分配的堆内存,在程序结束之前由于程序漏洞或其他原因没有释放,造成的内存浪费。

valgrind是Linux下,开放源代码(GPL V2)的仿真调试工具的集合。valgrind主要包含memcheck、callgrind、cachegrind等工具。其中,Memcheck是最常用的工具,用来检测程序中出现的内存问题,所有对内存的读写都会被检测到,一切对malloc() / free() / new / delete 的调用都会被捕获。

使用valgrind工具进行内存泄漏检查,重点需要释放的内存:

  • 对未初始化内存的使用;
  • 读/写释放后的内存块;
  • 读/写超出malloc分配的内存块;
  • 读/写不适当的栈中内存块;
  • 内存泄漏,指向一块内存的指针永远丢失;
  • 不正确的malloc/free或new/delete匹配;
  • memcpy()相关函数中的dst和src指针重叠。

1. 前期准备

1.1 valgrind下载安装

从valgrind官网http://valgrind.org/downloads/进行下载到本地后,进行解压到文件夹valgrind。
接下来,编译安装三件套:

cd valgrind
./configure
make
sudo make install

三件套完成后,查看是否安装成功:
在这里插入图片描述

1.2 在Clion中使用valgrind

在设置->编译、执行、部署->动态分析工具->Valgrind下增加valgrind的可执行文件(远程的也可以):
使用valgrind进行内存泄漏检测_第1张图片
完成后,点击在这里插入图片描述直接使用valgrind memcheck运行程序。(valgrind并不是边执行边检测,因此只有在结束程序之后,才能得到最终的内存泄漏情况)

2. 内存泄漏检查

2.1 内存分配

函数中的局部变量在栈内存中分配,以栈帧的形式。在函数结束之后,分配的局部变量全部出栈后释放内存。但直接在堆中分配的内存,在程序中不会自动释放,在变量使用结束之后,程序员需要借助free函数释放内存。

直接分配:malloc( )

malloc( )在堆上进行内存分配,函数返回值将申请内存空间首地址赋给指针。因为malloc函数返回值是一个内存地址,所以保存堆内存的变量必须是一个指针。

int *pmem = NULL;
pmem = (int *)molloc(sizeof(int));

在函数内malloc的变量可以传递给项目中的其他变量,因此在free时需要注意最终使用该堆内存的变量。

间接分配:函数传递

间接分配可以分为两种情况,两种情况的原理其实是一致的。
第一种是直接作为函数返回值,如下列代码中的res指针:

int *res;
int* test(para1, para2 ...) {
	int *pmem = NULL;
	pmem = (int*)malloc(sizeof(int));
	...
	return pmem;
}
res = test(...);

第二种情况是作为函数参数传递,如下列代码中的res指针:

int *res = NULL;
void mem_func(int *src_ptr, ...) {
  src_ptr = (int *)molloc(sizeof(int));
  ...
}
mem_func(res, ...);

2.2 泄漏检测

在进程运行结束之后,valgrind在一段时间后会产生结果,如下图所示:
使用valgrind进行内存泄漏检测_第2张图片
其中,InvalidRead并不会产生内存泄漏,Leak_PossiblyLost可能是线程并发造成的,也不用在意。Leak_DefinitelyLost是真实存在的内存泄漏问题,在vg_replace_malloc下产生的警告就是未被free掉的malloc分配的堆内存,需要逐个解决。展开警告的框架信息:
使用valgrind进行内存泄漏检测_第3张图片
由上往下是依次调用的关系,因此可以按照这个顺序去寻找应该增加free的定位。一般来说,可以直接看由上而下第一个自己写的函数,大概率就是这个函数出了问题…因为已有的库函数应该不会出现这种错误。
(使用uthash的代码需要注意,在hash表项使用结束之后,需要同时进行HASH_DEL和free函数处理)

你可能感兴趣的:(linux,c语言)