Valgrind 的介绍

  Valgrind 可以用来检测程序是否有非法使用内存的问题,例如访问未初始化的内存、访问数组时越界、忘记释放动态内存等问题。在 Linux 可以使用下面的命令安装 Valgrind:

1
2
3
4
5
6
$ wget ftp://sourceware.org/pub/valgrind/valgrind-3.13.0.tar.bz2
$ bzip2 -d valgrind-3.13.0.tar.bz2
$ tar -xf valgrind-3.13.0.tar
$ cd valgrind-3.13.0
$ ./configure && make
$ sudo make install

检测内存泄漏

  Valgrind 可以用来检测程序在哪个位置发生内存泄漏,例如下面的程序:

1
2
3
4
5
6
7
8
#include <stdlib.h>
 
int main()
{
int *array = malloc(sizeof(int));
 
return 0;
}

  编译程序时,需要加上-g选项:

1
$ gcc -g -o main_c main.c

  使用 Valgrind 检测内存使用情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ valgrind --tool=memcheck --leak-check=full ./main_c
==31416== Memcheck, a memory error detector
==31416== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31416== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31416== Command: ./main_c
==31416==
==31416==
==31416== HEAP SUMMARY:
==31416== in use at exit: 4 bytes in 1 blocks
==31416== total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==31416==
==31416== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31416== at 0x4C2DBF6: malloc (vg_replace_malloc.c:299)
==31416== by 0x400537: main (main.c:5)
==31416==
==31416== LEAK SUMMARY:
==31416== definitely lost: 4 bytes in 1 blocks
==31416== indirectly lost: 0 bytes in 0 blocks
==31416== possibly lost: 0 bytes in 0 blocks
==31416== still reachable: 0 bytes in 0 blocks
==31416== suppressed: 0 bytes in 0 blocks
==31416==
==31416== For counts of detected and suppressed errors, rerun with: -v
==31416== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

  先看看输出信息中的HEAP SUMMARY,它表示程序在堆上分配内存的情况,其中的1 allocs表示程序分配了 1 次内存,0 frees表示程序释放了 0 次内存,4 bytes allocated表示分配了 4 个字节的内存。
  另外,Valgrind 也会报告程序是在哪个位置发生内存泄漏。例如,从下面的信息可以看到,程序发生了一次内存泄漏,位置是main.c文件的第 5 行:

1
2
3
==31416== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==31416== at 0x4C2DBF6: malloc (vg_replace_malloc.c:299)
==31416== by 0x400537: main (main.c:5)

  Valgrind 也可以用来检测 C++ 程序的内存泄漏,下面是一个正常的 C++ 程序,没有发生内存泄漏:

1
2
3
4
5
6
7
8
9
#include <string>
 
int main()
{
auto ptr = new std::string("Hello, World!");
delete ptr;
 
return 0;
}

  使用 Valgrind 分析这段程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./main_cpp
==31438== Memcheck, a memory error detector
==31438== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31438== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31438== Command: ./main_cpp
==31438==
==31438==
==31438== HEAP SUMMARY:
==31438== in use at exit: 72,704 bytes in 1 blocks
==31438== total heap usage: 2 allocs, 1 frees, 72,736 bytes allocated
==31438==
==31438== 72,704 bytes in 1 blocks are still reachable in loss record 1 of 1
==31438== at 0x4C2DBF6: malloc (vg_replace_malloc.c:299)
==31438== by 0x4EC3EFF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==31438== by 0x40104E9: call_init.part.0 (dl-init.c:72)
==31438== by 0x40105FA: call_init (dl-init.c:30)
==31438== by 0x40105FA: _dl_init (dl-init.c:120)
==31438== by 0x4000CF9: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so)
==31438==
==31438== LEAK SUMMARY:
==31438== definitely lost: 0 bytes in 0 blocks
==31438== indirectly lost: 0 bytes in 0 blocks
==31438== possibly lost: 0 bytes in 0 blocks
==31438== still reachable: 72,704 bytes in 1 blocks
==31438== suppressed: 0 bytes in 0 blocks
==31438==
==31438== For counts of detected and suppressed errors, rerun with: -v
==31438== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

  使用 Valgrind 分析 C++ 程序时,有一些问题需要留意。例如,这个程序并没有发生内存泄漏,但是从HEAP SUMMARY可以看到,程序分配了 2 次内存,但却只释放了 1 次内存,为什么会这样呢?
  实际上这是由于 C++ 在分配内存时,为了提高效率,使用了它自己的内存池。当程序终止时,内存池的内存才会被操作系统回收,所以 Valgrind 会将这部分内存报告为 reachable 的,需要注意,reachable 的内存不代表内存泄漏,例如,从上面的输出中可以看到,有 72704 个字节是 reachable 的,但没有报告内存泄漏。

检测越界访问

  C++ 程序经常出现的 Bug 就是数组越界访问,例如下面的程序出现了越界访问:

1
2
3
4
5
6
7
8
9
10
#include <vector>
#include <iostream>
 
int main()
{
std::vector<int> v(10, 0);
std::cout << v[10] << std::endl;
 
return 0;
}

  使用 Valgrind 分析这段程序,Valgrind 会提示越界访问:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ g++ -std=c++11 -g -o main_cpp main.cpp
$ valgrind --tool=memcheck --leak-check=full ./main_cpp
==31523== Memcheck, a memory error detector
==31523== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31523== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31523== Command: ./main_cpp
==31523==
==31523== Invalid read of size 4
==31523== at 0x400AD7: main (main.cpp:7)
==31523== Address 0x5ab5ca8 is 0 bytes after a block of size 40 alloc'd
==31523== at 0x4C2E216: operator new(unsigned long) (vg_replace_malloc.c:334)
==31523== by 0x4010D3: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (new_allocator.h:104)
==31523== by 0x401040: std::allocator_traits<std::allocator<int> >::allocate(std::allocator<int>&, unsigned long) (alloc_traits.h:491)
==31523== by 0x400F91: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) (stl_vector.h:170)
==31523== by 0x400E7E: std::_Vector_base<int, std::allocator<int> >::_M_create_storage(unsigned long) (stl_vector.h:185)
==31523== by 0x400D1E: std::_Vector_base<int, std::allocator<int> >::_Vector_base(unsigned long, std::allocator<int> const&) (stl_vector.h:136)
==31523== by 0x400C11: std::vector<int, std::allocator<int> >::vector(unsigned long, int const&, std::allocator<int> const&) (stl_vector.h:291)
==31523== by 0x400AB9: main (main.cpp:6)

  Invalid read of size 4表示越界读取 4 个字节,这个操作出现在main.cpp文件的第 7 行。另外可以看到,vector分配了一块 40 字节的内存,程序越界访问紧急着这块内存之后的 4 个字节。

检测未初始化的内存

  另一种经常出现的 Bug,就是程序访问了未初始化的内存。例如:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
 
int main()
{
int x;
if (x == 0)
{
std::cout << "X is zero" << std::endl;
}
 
return 0;
}

  使用 Valgrind 检测这个程序:

1
2
3
4
5
6
7
8
9
$ g++ -std=c++11 -g -o main_cpp main.cpp
$ valgrind --tool=memcheck --leak-check=full ./main_cpp
==31554== Memcheck, a memory error detector
==31554== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==31554== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==31554== Command: ./main_cpp
==31554==
==31554== Conditional jump or move depends on uninitialised value(s)
==31554== at 0x400852: main (main.cpp:6)

  输出中提示了main.cpp文件的第 6 行访问了未初始化的内存。

使用 Valgrind 检测 C++ 内存泄漏的更多相关文章

  1. 使用android studio检测app内存泄漏【转载】

    Android开发中难免会遇到各种内存泄漏,如果不及时发现处理,会导致出现内存越用越大,可能会因为内存泄漏导致出现各种奇怪的crash,甚至可能出现因内存不足而导致APP崩溃. 一般检测android ...

  2. Valgrind 检测程序内存使用

    Valgrind是用于构建动态分析工具的探测框架.它包括一个工具集,每个工具执行某种类型的调试.分析或类似的任务,以帮助完善你的程序.Valgrind的架构是模块化的,所以可以容易地创建新的工具而又不 ...

  3. valgrind检查代码内存泄漏,5种内存泄漏情况

    摘要: valgrind是linux下用于调试程序和查找内存泄露的常用工具.valgrind会报告5种内存泄露,"definitely lost", "indirectl ...

  4. valgrind检查C++内存泄漏

    valgrind --tool=memcheck --leak-check=full ./httptest Valgrind 使用 用法: valgrind [options] prog-and-ar ...

  5. valgrind 代码检查,内存泄漏

    使用平台 linux 下载 http://valgrind.org/ 文档 http://valgrind.org/docs/manual/manual.html 博客 https://www.osc ...

  6. 如何在linux下检测内存泄漏

    之前的文章应用 Valgrind 发现 Linux 程序的内存问题中介绍了利用Linux系统工具valgrind检测内存泄露的简单用法,本文实现了一个检测内存泄露的工具,包括了原理说明以及实现细节. ...

  7. C++内存泄漏检测工具

    C++内存泄漏检测工具 1.VC自带的CRT:_CrtCheckMemory   调试器和 CRT 调试堆函数 1.1用法: /************************************ ...

  8. c/c++通用内存泄漏检测框架GMFD(General Memory Fault Detection Framework)

    http://qa.baidu.com/blog/?p=171 1 背景: x86平台有完善的用户态检测内存工具比如valgrind等,可以监控程序运行中详细的内存信息,从而精确定位内存问题.然而随着 ...

  9. 使用 Android Studio 检测内存泄漏与解决内存泄漏问题

    本文在腾讯技术推文上 修改 发布. http://wetest.qq.com/lab/view/63.html?from=ads_test2_qqtips&sessionUserType=BF ...

随机推荐

  1. SSO单点登录和CAS

    一.单点登录流程 =====客户端====== 1.拦截客户端的请求判断是否有局部的session 2.1如果有局部的session,放行请求. 2.2如果没有局部session 2.2.1请求中有携 ...

  2. 使用Debug Diagnostic Tool排除内存泄漏故障

    在我之前的博文中(SQL Server内存泄漏),我解释了如何使用“!heap”命令识别哪个模块泄漏了内存.有时我们使用“!d”命令来找到模型或者使用搜索内存命令(s)不能通过显示内存找到原因. 在这 ...

  3. 2.InfluxDB-InfluxQL基础语法教程--目录

    本文翻译自官网,官方文档地址:(https://docs.influxdata.com/influxdb/v1.7/query_language/data_exploration/) InfluxQL ...

  4. Django 练习班级管理系统三 -- 分页

    在 user_manager 项目下创建一个 python package:utils,里面创建一个 page.py 文件 page.py 文件内容为: # 创建一个 PagerHelper 类 cl ...

  5. Properties类按顺序输出加载内容

    Properties类按顺序输出加载内容 最近手写工厂的时候,遇到了加载配置文件时不按照properties文件中的数据的顺序来加载. 一.问题代码 import java.io.IOExceptio ...

  6. Windows出现“引用账户被锁定,且暂时无法登录”解决方法

    1. 问题描述如下: i. 远程桌面登录时,出现提示必须修改密码才能登录,是因为密码过期所导致的,如下图: ii. 当我们登录Windows控制台(基于OpenStack平台的虚拟机)进行修改密码时, ...

  7. E07【餐厅】What would you recommend?

    核心句型 What would you recommend? 你有什么推荐吗? 场景对话: A:What do  you  want  to  eat? 你想吃点什么? B:I don't know. ...

  8. 201871010126 王亚涛 《面向对象程序设计JAVA》第十四周学习总结

    内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p/11 ...

  9. flask中利用session实现用户记住密码

    “记住密码”的实质,实际上就是把cookie的有效期设置的长一点,当用户没有选择记住密码时,cookie的有效期为会话结束,选择记住密码后,会根据服务器的设置延长cookie的有效期,默认是31天.在 ...

  10. zz京东电商推荐系统实践

    挺实在 今天为大家分享下京东电商推荐系统实践方面的经验,主要包括: 简介 排序模块 实时更新 召回和首轮排序 实验平台 简介 说到推荐系统,最经典的就是协同过滤,上图是一个协同过滤的例子.协同过滤主要 ...