linux valgrind安装及使用

Valgrind 是一个编程工具,主要用于内存调试、内存泄漏检测以及性能分析。它是开源的,并且跨平台,可以在 Linux、macOS 和其他类 Unix 系统上运行。Valgrind 最为人知的功能之一是它的内存检测器(Memcheck),它可以检测 C 和 C++ 程序中的内存管理问题,比如使用未初始化的内存、读写释放后的内存(野指针)、内存泄漏等。

主要功能 

1、内存检测(Memcheck)

检查程序中的内存问题,如泄漏、越界、非法指针等。

2、Cachegrind

分析CPU的cache命中率、丢失率,用于进行代码优化。

3、Callgrind

主要用来检查程序中函数调用过程中出现的问题,可以生成调用图。

4、Helgrind
检测多线程程序中的同步错误,如数据竞争、死锁等。

5、Massif
主要用来检查程序中堆栈使用中出现的问题。

源码下载:点击跳转

编译及安装:

tar -xf valgrind-3.23.0.tar.bz2
cd valgrind-3.23.0/
./configure
make -j8
sudo make install

实例1:检测内存访问错误

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
	const int size=100;
	int n,sum=0;
	int *A= (int*)malloc( sizeof(int)*size );
	
	for(n=size;n>0;n--)/*walk through A[100]...A[1]*/
		A[n]= n;/*error:A[100]invalid write*/
	for (n=0;n<size;n++)/*walk through A[0]...A[99]*/
		sum += A[n];/*error:A[0]not initialized */
	printf("sum =% d\n", sum);
	return 0;/* mem leak:A[]*/
}

编译带有调试信息的程序,在Valgrind 中运行:

gcc -g 1.c
valgrind --tool=memcheck --leak-check=yes ./a.out

下面进行分析Valgrind 报告的错误清单。

1.1 检测无效的写访问

        第一个(也可能是最严重的)错误是缓冲区溢出,即对数组元素A[100]的意外写访问。由于数组只有100个元素,因此最大的有效索引是99。A[100]指向未分配的内存位置,这个位置刚好在为数组A分配的内存后面。因此,Valgrind报告了“invalid write”错误:

        字符串==46644==是指进程ID,当Valgrind检查多个进程时,它很有用。重要的信息是 1.c 的第9行发生了无效写操作。其他信息还揭示了被分配的最近的内存块地址,以及它是如何分配的。内存调试器猜测第9行的无效写操作与此内存块有关。猜测是正确的,因为这两个内存块都属于同一数组A。
        注意,只有当使用malloc()或new为数组分配动态内存时,Valgrind才能够捕获到数组越界错误。本例正是这种情况,发生在第6行:

int *A= (int*)malloc( sizeof(int)*size );

        如果将第6行改写为int a[size],则A就是一个位于栈上的局部变量,而不在堆上。事实证明,Valgrind检测不到这样的错误,但Purify能够捕获它。这说明并非所有内存调试器都能够准确地报告相同的错误。

1.2 检测对未初始化的内存的读取操作

        1.c 中的下一个错误是读取了未初始化的内存。由于第8行的索引计算错误,element A[0]一直未被写入初始值。后面,第11行的语句sum += A[n]要读这个元素,这意味着变量sum也“被感染”了。
        要指出的重要一点是 Valgrind 何时报告这个未初始化的内存错误。sum的感染发生在第11行。但错误却不是在该时刻报告的,而是在后面第12行输出变量值时才报告的:

1.3 检测内存泄漏

最后一个bug是内存泄漏。程序的第6行通malloc(sizeof(int)*size)语句为数组A分配了内存,但一直没有相应的free(A)语句来删除它。在程序结束时,内存调试器报告了这个泄漏错误:

实例2:对内存分配/释放的不完整调用

第二个实例 2.c 演示了如何在一个使用了char*类型C字符串的程序中查找内存分配bug:

/* 2.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char*argv[]){
	char* mystr1=strdup("test");
	char* mystr2=strdup("TEST");
	mystr1=mystr2;
	
	printf("mystr1=%s\n",mystr1);
	free(mystr1);
	
	printf("mystr2=%s\n",mystr2);
	free(mystr2);
	return 0;
}

        strdup()函数返回其字符串参数的一个副本。它在堆上分配了必要的内存。调用函数过会儿负责释放这些内存。现在编译并运行程序:

gcc -g 2.c
valgrind --tool=memcheck --leak-check=yes ./a.out

        实际的错误发生在第8行的语句mystr1=mystr2。编码风格显示出在第8行之前,mystr1和mystr2都有单独分配的内存。之后,这两个变量指向了同一个内存位置。但是,代码里面并没有考虑这一点,因此随后发生了几个错误。
        第一个错误发生在第13行,即当输出mystr2的时候。由于第11行已经释放了分配的内存,因此mystr2现在是一个指向已释放内存的指针。在printf()语句中访问它就形成了一个无效的读取访问:

        注意,内存调试器给出了错误语句的位置(第13行),以及在何处进行了无效的内存释放(第11行)。
        下一个bug在第14行,它释放了mystr2指向的内存。这是非法的,因为在第11行已经释放了该内存:

   最后,还有一个内存泄漏。在第8行变量mystr1被更改之前,它一直指向在第6行为其分配的内存。这个内存一直未释放。由于不再有任何指针指向第6行中分配的这个内存位置,因此它成为一个内存泄漏。     

觉得有帮助的话,打赏一下呗。。

           

  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值