如何初步使用valgrind工具来检测内存泄露,堆栈空间,未初始化变量问题

简介: 如何初步使用valgrind工具来检测内存泄露,堆栈空间,未初始化变量问题

官方概念

Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。Valgrind由内核(core)以及基于内核的其他调试工具组成。内核类似于一个框架(framework),它模拟了一个CPU环境,并提供服务给其他工具;而其他工具则类似于插件  (plug-in),利用内核提供的服务完成各种特定的内存调试任务。

Valgrind 体系结构

Valgrind包括如下一些工具:

◼  Memcheck。这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够
发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已
经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分。

◼  Callgrind。它主要用来检查程序中函数调用过程中出现的问题。

◼  Cachegrind。它主要用来检查程序中缓存使用出现的问题。

◼  Helgrind。它主要用来检查多线程程序中出现的竞争问题。

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

◼  Extension。可以利用core提供的功能,自己编写特定的内存调试工具。

写一个例子,内存泄露

sample.c

#include <stdio.h>
#include <stdlib.h>
void fun( )
{
    int *p = (int *)malloc(10*sizeof(int));
    p[11] = 0; // 此处越界
    free(p);
}
int main(void)
{
    fun(); 
    return 0;
}

gcc -g -o sample sample.c    -- 使用-g 加上调试

valgrind --tool=memcheck ./sample

valgrind 会提示 哪一行出了问题

1.  这是一个对内存的非法写操作,非法写操作的内存是4 bytes。

2.  发生错误时的函数堆栈,以及具体的源代码行号。

3.  非法写操作的具体地址空间。


在例如,把上面的例子,malloc的内存,不free

#include <stdio.h>
#include <stdlib.h>
void fun( )
{
    int *p = (int *)malloc(10*sizeof(int));
    p[11] = 0; // 此处越界
    //free(p);
}
int main(void)
{
    fun(); 
    return 0;
}

1块内存被分配,0块内存被释放   -- 内存泄露

 

第2个demo,未初始化的变量

badloop.c

#include <stdio.h>
int main(void)
{
    int a[5];
    int i, s;//s为局部变量,且为初始化
    a[0] = a[1] = a[2] = a[3] = a[4] = 0;
    for (i = 0; i < 5; i++)
    {
        s += a[i]; //使用了未初始化的变量,结果未知
    }
    if (s == 888)
    {
        printf("sum is %d\n", s);
    }
    return 0;
}

gcc -g -o badloop badloop.c

valgrind --tool=memcheck ./badloop

动态内存管理错误

mem.c

#include <stdio.h>
#include <stdlib.h>
int main(void)   
{   
  char * p = (char *)malloc(10);
  char *pt = p;
  for(int i = 0;i<10;i++)
  {
    p[i] = i;
  }
  delete p ;  //使用c++ 的 delete 去释放p ,delete 是兼容c语言的 释放内存机制的
  *pt = 'o';
  free(pt);
     return 0;   
 }

g++ -g -o mem mem.c

valgrind --tool=memcheck ./mem

常见的内存动态管理错误包括:

◼  申请和释放不一致

由于  C++ 兼容  C,而  C 与  C++ 的内存申请和释放函数是不同的,因此在  C++ 程

序中,就有两套动态内存管理函数。一条不变的规则就是采用  C 方式申请的内存就用

C 方式释放;用  C++ 方式申请的内存,用  C++ 方式释放。也就是用  malloc/alloc/realloc

方式申请的内存,用  free 释放;用  new 方式申请的内存用  delete 释放。在上述程序

中,用  malloc 方式申请了内存却用  delete 来释放,虽然这在很多情况下不会有问题,

但这绝对是潜在的问题。

◼  申请和释放不匹配

申请了多少内存,在使用完成后就要释放多少。如果没有释放,或者少释放了就是

内存泄露;多释放了也会产生问题。上述程序中,指针p和pt指向的是同一块内存,却

被先后释放两次。

◼  释放后仍然读写

本质上说,系统会在堆上维护一个动态内存链表,如果被释放,就意味着该块内存

可以继续被分配给其他部分,如果内存被释放后再访问,就可能覆盖其他部分的信息,

这是一种严重的错误。

 

c++中的内存泄露问题

badleak1.cpp

#include <iostream>
#include <vector>
class Item
{
 public:
    Item()
    {
        printf("构造Item\n");
    }
    ~Item()
    {
        printf("析构Item\n");
    }
};
int main(void)
{
    std::vector<Item*> vItem;
    for(int i= 0; i < 2; i++)
    {
        Item *item = new Item();
        vItem.push_back(item);
    }
    return 0;
}

g++ -g -o badleak badleak.cpp -std=c++11

valgrind ./badleak

new 出来的内存,没有delete 释放 ,出现内存泄露,valgrind检测出来了

 

看看下面这个demo,使用智能指针修饰一下

 

badleak2.cpp

g++ -g -o badleak badleak2.cpp -std=c++11

valgrind ./badleak2

#include <iostream>
#include <vector>
#include <memory>
using namespace std;
class Item
{
    public:
    Item()
    {
        printf("构造Item\n");
    }
    ~Item()
    {
        printf("析构Item\n");
    }
};
int main(void)
{
    vector<shared_ptr<Item>> vitem;
  for(int i = 0 ;i<2;i++){
    shared_ptr<Item> item = shared_ptr<Item>(new Item());
        //也可以 shared_ptr<Item> item = make_shared<Item>();
    vitem.push_back(item);
  }
    return 0;
}

问题解决

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

相关文章
|
22天前
|
存储 Linux Android开发
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility 是一个完全开源的工具,用于从内存 (RAM) 样本中提取数字工件。支持Windows,Linux,MaC,Android等多类型操作系统系统的内存取证。针对竞赛这块(CTF、技能大赛等)基本上都是用在Misc方向的取证题上面,很多没有听说过或者不会用这款工具的同学在打比赛的时候就很难受。以前很多赛项都是使用vol2.6都可以完成,但是由于操作系统更新,部分系统2.6已经不支持了,如:Win10 等镜像,而Volatility3是支持这些新版本操作系统的。
|
11天前
|
存储 设计模式 Java
JavaSE 面向对象程序设计初级 2024方法变量封装javabean结合内存图详解
JavaSE 面向对象程序设计初级 2024方法变量封装javabean结合内存图详解
19 7
|
14天前
|
C++
内存泄漏检查工具下载(vld)
内存泄漏检查工具下载(vld)
|
16天前
|
Java Linux PHP
【应急响应】后门攻击检测指南&Rookit&内存马&权限维持&WIN&Linux
【应急响应】后门攻击检测指南&Rookit&内存马&权限维持&WIN&Linux
|
2月前
|
算法 Java Python
【Python 的内存管理机制专栏】Python 内存管理实战:性能优化与内存泄漏检测
【5月更文挑战第18天】Python内存管理关乎程序性能与稳定性。优化包括避免过多临时对象,如优化列表推导式减少对象创建。警惕循环引用造成的内存泄漏,如示例中的Node类。使用`gc`模块检测泄漏,通过`gc.set_debug(gc.DEBUG_LEAK)`和`gc.collect()`获取信息。实践中需持续分析内存使用,优化算法、数据结构和资源释放,以提升程序质量与效率。
【Python 的内存管理机制专栏】Python 内存管理实战:性能优化与内存泄漏检测
|
2月前
|
存储 Java 程序员
【Python 的内存管理机制专栏】深入解析 Python 的内存管理机制:从变量到垃圾回收
【5月更文挑战第18天】Python内存管理关乎程序性能与稳定性,包括变量存储和垃圾回收。变量存储时,如`x = 10`,`x`指向内存中值的引用。垃圾回收通过引用计数自动回收无引用对象,防止内存泄漏。了解此机制可优化内存使用,避免循环引用等问题,提升程序效率和稳定性。深入学习内存管理对成为优秀Python程序员至关重要。
【Python 的内存管理机制专栏】深入解析 Python 的内存管理机制:从变量到垃圾回收
|
3天前
|
存储 JavaScript 前端开发
面试官:JS中变量定义时内存有什么变化?
面试官:JS中变量定义时内存有什么变化?
|
7天前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
13 0
|
1月前
|
监控 Linux 测试技术
edac是检测什么的,和centos内存条损害检测工具
【6月更文挑战第1天】edac是检测什么的,和centos内存条损害检测工具
37 2
|
2月前
|
JSON 数据管理 测试技术
自动化测试工具Selenium Grid的深度应用分析深入理解操作系统的内存管理
【5月更文挑战第28天】随着互联网技术的飞速发展,软件测试工作日益复杂化,传统的手工测试已无法满足快速迭代的需求。自动化测试工具Selenium Grid因其分布式执行特性而受到广泛关注。本文旨在深入剖析Selenium Grid的工作原理、配置方法及其在复杂测试场景中的应用优势,为测试工程师提供高效测试解决方案的参考。