还在为查内存泄漏问题痛苦不堪?试试这个神器

自信、冷静、专注。 —— TM 熊的自我勉励

在这里插入图片描述

1 背景

在 C/C++软件开发中,不可避免的会遇到内存操作,如果操作不当,很容易造成内存泄漏,对于简单的代码工程,我们可以去检查代码中 new 和 delete 的匹配对数就基本能定位到问题,但是这样的方法对于代码量以万为单位的系统级工程会是致命的,这时我们就需要用到一些内存检测工具,今天我们推荐 Valgrind,一款非常好用的开源内存管理框架,通过实例看看 Valgrind 在内存检测上的简便性和可靠性.

2 常见的内存异常操作

  • 申请的内存未释放
  • 使用未初始化的内存(使用野指针)
  • 对释放后的内存读/写(使用野指针)
  • 动态内存越界
  • 不匹配地使用 malloc/new/new[] 和 free/delete/delete[]
  • 重复释放内存

3 Valgrind 简介

Valgrind 是运行在 Linux 上一套基于仿真技术的程序调试和分析工具。它包含一个内核——一个软件合成的 CPU,和一系列的小工具,每个工具都可以完成一项任务——调试,分析,或测试等。Valgrind 可以检测内存泄漏和内存越界,还可以分析 cache 的使用等,灵活轻巧而又强大。Valgrind 包含以下工具

  • Memcheck:检查程序中的内存问题,如泄漏、越界、非法指针等。
  • Callgrind:检测程序代码覆盖,以及分析程序性能。
  • Cachegrind:分析 CPU 的 cache 命中率、丢失率,用于进行代码优化。
  • Helgrind:用于检查多线程程序的竞态条件。
  • DRD: 也是线程错误检测器。它与 Helgrind 类似,但使用不同的分析技术,因此可能会发现不同的问题
  • Massif:堆栈分析器,指示程序中使用了多少堆内存等信息。
  • DHAT: 是一种不同类型的堆分析器。它可以帮助您了解块寿命,块利用率和布局效率低下的问题
  • SGcheck: 一种实验工具,可以检测堆栈和全局数组的溢出。它的功能与 Memcheck 的功能互补:SGcheck 发现 Memcheck 无法解决的问题,反之亦然
  • BBV: 一个实验性的 SimPoint 基本块矢量生成器。它对进行计算机体系结构研究和开发的人很有用
  • Lackey: 一个示例工具,用于说明一些仪器基础知识
  • Nulgrind: 最小的 Valgrind 工具,不进行分析或检测,仅用于测试目的

即 Valgrind 其实是一个工具集,内存错误检测只是它众多功能的一个,但我们用得最多的功能正是它——memcheck。而学会用 Valgrind 的 memcheck 也正是我们今天的主题。

4 Valgrind 的下载与安装

最新版本链接http://valgrind.org/downloads/valgrind-3.16.0.tar.bz2

Linux 下 Valgrind 的安装

1. tar -jxvf valgrind-3.16.0.tar.bz2
2. cd valgrind-3.16.0
3. ./configure
4. make
5. sudo make install

5 Valgrind 检查程序中的内存问题

  • 运行环境:centOS6.9
  • 以下代码在编译时加上-g 选项

5.1 申请的内存未释放

#include <stdio.h>
#include <stdlib.h>

int *func()
{
	return (int *)malloc(sizeof(int));
}

int main()
{
	int *p = func();
	*p = 100;

	return 0;
}


可以看到 valgrind 工具的提示:分配了1次四字节内存,释放0次,并标定了申请内存的代码行号。

5.2 使用未初始化的内存(使用野指针)

#include <stdio.h>

int main()
{
  int *p;
  
  int  a = *p;  //第7行

  return 0;
}


可以看到 valgrind 工具的提示:在代码的第7行使用了未初始化的指针,且程序中未出现内存泄漏。

5.3 对释放后的内存读/写(使用野指针)

#include <stdlib.h>
#include <string.h>

int *func()
{
	return (int *)malloc(sizeof(int));
}

int main()
{
	int a = 0;
	int *p = func();

	*p = 100;
        free(p);    //第15行

	a = *p;     //第17行
	return 0;
}

可以看到 valgrind 工具的提示:第17行错误读取*p的值,此时可用空间是0字节,因为指针p已经在第15行被释放了,同时提示该程序是没有内存泄漏的。

5.4 动态内存越界

#include <stdlib.h>
#include <string.h>

int main()
{
	int *str1 = (int *)malloc(sizeof(int)*10);

	str1[10] = 100;     //第8行

	free(str1);
	return 0;
}


可以看到 valgrind 工具的提示:在第8行有越界访问。
注意: valgrind并不会对在栈上分配的数组越界行为做检查,如下面的例子

#include <stdlib.h>
#include <string.h>

int main()
{
	int str2[10] = {0};

	str2[10] = 200;
	return 0;
}

5.5 不匹配地使用 malloc/new/new[] 和 free/delete/delete[]

#include <stdlib.h>
#include <string.h>

int *func()
{
	return (int *)malloc(sizeof(int));  //第6行
}

int main()
{
	int *p = func();    //第11行
	*p = 100;

	delete p;   //第14行
	return 0;
}


可以看到 valgrind 工具的提示:第14行不匹配Mismatched,用malloc分配内存,却用delete释放内存,应该用free。

5.6 重复释放内存

#include <stdlib.h>
#include <string.h>

int *func()
{
	return (int *)malloc(sizeof(int));
}

int main()
{
	int *p = func();
	*p = 100;

	free(p);    //第14行
	free(p);    //第15行
	return 0;
}


可以看到 valgrind 工具的提示:第15行有一个错误释放,因为第14行时就已经释放掉p指针了,同时提示程序1次malloc,2次free


絮叨

南极熊club专注于嵌入式与物联网领域。由于刚刚创立,一定会存在很多不足的地方,无论是写作风格还是内容上,欢迎大家提出批评与建议。学习不是为了变得全知全能,而是为了不再害怕未知,我是熊二,我们下期见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值