热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【原创】Valgrind基础

Valgrind概述Valgrind是一种用于构建动态分析工具集的框架;Valgrind工具能够自动探测许多种类的内存管理bug和线程bug,能够帮助你

Valgrind 概述

Valgrind 是一种用于构建动态分析工具集的框架; 
Valgrind 工具能够自动探测许多种类的内存管理 bug 和线程 bug ,能够帮助你在细微处进行程序调优; 
你可以基于 Valgrind 构建新工具集; 

Valgrind 当前发布版包含了六种产品质量相关工具: 
  • 一种内存错误探测器
  • 两种线程错误探测器
  • 一种 cache 和分支预测分析工具
  • 一种 call-graph generating cache 和分支预测分析工具
  • 一种堆分析工具
Valgrind 还包含了三种实验性工具: 
  • heap/stack/global 数组越界探测器
  • a second heap profiler that examines how heap blocks are used
  • a SimPoint basic block vector generator
Valgrind 与 CPU 、操作系统,以及编译器和基础 C 库都是强相关的;移植 Valgrind 是比较困难的。 
尽管如此,Valgrind 已经支持如下各种平台: 
  • - X86/Linux
  • - AMD64/Linux
  • - PPC32/Linux
  • - PPC64/Linux
  • - ARM/Linux
  • - x86/MacOSX
  • - AMD64/MacOSX
  • - S390X/Linux
  • - MIPS32/Linux
  • - MIPS64/Linux
Note that AMD64 is just another name for x86_64 , and Valgrind runs fine on Intel processors.   
Also note that the core of MacOSX is called " Darwin " and this name is used sometimes. 

Valgrind is licensed under the GNU General Public License, version 2. 
However: if you contribute code, you need to make it available as GPL version 2 or later, and not 2-only. 

Valgrind  源码安装

基于 tar.bz2 源码包的安装: 
  1. Run ./configure, with some options if you wish.  The only interesting one is the usual --prefix=/where/you/want/it/installed.
  2. Run "make".
  3. Run "make install", possibly as root if the destination permissions require that.
  4. See if it works.  Try "valgrind ls -l".  Either this works, or it bombs out with some complaint. 
Important !  Do not move the valgrind installation into a place different from that specified by --prefix at build time.  
This will cause things to break in subtle ways, mostly when Valgrind handles fork/exec calls. 

Valgrind 工具套装

The Valgrind distribution includes the following debugging and profiling tools: 

Memcheck 
Memcheck 用于探测程序中存在的内存管理问题,主要针对 C 和 C++ 程序; 
当程序运行在 Memcheck 监控之下时,所有针对内存的读写操作都将被检查,所有 malloc/new/free/delete 调用都会被拦截; 
因此,Memcheck 能够探测到你的程序是否存在以下的问题: 
  • Accesses memory it shouldn't (areas not yet allocated, areas that have been freed, areas past the end of heap blocks, inaccessible areas of the stack).
    访问了不该访问的内存(尚未分配过的区域;已经被释放掉的区域;超过堆块边界的区域;栈中不可访问的区域)
  • Uses uninitialised values in dangerous ways.
    以危险方式使用未初始化的值
  • Leaks memory.
    存在内存泄露
  • Does bad frees of heap blocks (double frees, mismatched frees).
    针对堆块执行了错误的 free 行为(double free 或 mismatched free)
  • Passes overlapping source and destination memory blocks to memcpy() and related functions.
    基于 memcpy() 或其他相关函数操作了存在重叠的源和目的地址所指向的内存块;
Memcheck 会在遇到上述错误的时候立即进行报告,同时给出错误发生对应的源码行号,以及触发该错误时对应的函数调用栈; 
Memcheck 是基于字节进行寻址跟踪,基于比特进行 value 的初始化跟踪;所以,其可以探测出单独一比特未初始化数据的使用,而不会作为比特运行错误进行报告; 
基于 Memcheck 运行程序时将会比常规运行慢 10-30 倍; 

Cachegrind 
Cachegrind 是一种 cache 分析工具; 
Cachegrind 能够针对 CPU 进行 I1, D1 和 L2 cache 的详细模拟,并精确的定位出代码中导致 cache miss 的地方; 
Cachegrind 能够确定出 cache miss 的次数、内存引用情况,以及会触发 cache miss 的每一行代码,每一个函数,每一个模块,并给出整个程序的情况摘要; 
Cachegrind 对于任何语言编写的程序都非常有用; 
基于 Cachegrind 运行程序时将会比常规运行慢 20-100 倍; 

Callgrind 
Callgrind 是针对 Cachegrind 的扩展; 
Callgrind 提供了 Cachegrind 所能提供的全部信息,还额外提供了关于 callgraphs 的信息; 
Callgrind 在 Valgrind 的 3.2.0 主发布版中被加入; 
另外还有一个名为 KCachegrind 的可视化工具,可以对 Callgrind 收集到的信息尽心更好的展示; 

Massif 
Massif 是一种堆分析工具; 
Massif 通过对程序堆获取常规快照,进而展开详细堆分析; 
Massif 能够生成随时间变化的堆使用图,其中会给出程序的哪些部分进行了绝大部分的内存分配操作; 
作为图的补充,通过 text 或 HTML 文件能够确定分配内存最多地方的更多信息; 
基于 Massif 运行程序时将会比常规运行慢 20 倍; 

Helgrind 
Helgrind 是一种线程调试器,用于查找多线程程序中的数据竞争; 
Helgrind 会查出特定类型内存的位置:被多于一个(POSIX p-)thread 所访问,但是却没有发现保证访问一致性的锁; 
这类位置已经隐式表明了多线程同步的缺失,将会导致非常难于发现的时序问题; 
Helgrind 对于任何使用 pthreads 的程序都非常有用; 

DRD 
DRD 是一种检测多线程 C 和 C++ 程序错误的工具; 
DRD 对于任何使用 POSIX 线程原语的程序有效;或对于任何构建与 POSIX 线程原语之上的、使用线程概念的程序有效; 
尽管 Helgrind 能够检测出锁定顺序违反等问题,但对于大部分程序来说,DRD 在进行分析时将花费更少的内存; 

Lackey, Nulgrind 
Lackey and Nulgrind are also included in the Valgrind distribution. They don't do very much, and are there for testing and demonstrative purposes. 

Other Tools 
Several other Valgrind tools have been created: you can find a list of them on the Variants / Patches page. 

FAQ 摘译

1.1. How do you pronounce "Valgrind"? 
The "Val" as in the word "value". The "grind" is pronounced with a short 'i' -- ie. "grinned" (rhymes with "tinned") rather than "grined" (rhymes with "find"). 

4.4. My program crashes normally, but doesn't under Valgrind, or vice versa. What's happening? 
基于 valgrind 运行目标程序和直接运行目标程序两种方式存在些许不同;例如,内存布局会不同,线程调度方式会不同 

      在大多数情况下,上述差异不会导致什么问题,但当你的程序本身存在 bug 的时候,可能会遇到一些问题。例如,如果你的程序原本会崩溃于错误的访问了非法内存地址的情况,而在基于 valgrind 运行时可能,该地址可能就是合法的内存地址了。另一种情况是,如果你的程序存在数据竞争,但在 valgrind 下可能不会显现出来。 

      对于上面的情况,你是无法做出任何应对的,因为这就是 valgrind 的工作方式,即 valgrind 无法精确的复制出可执行程序的本地执行环境。当出现你的程序崩溃于内存错误,但在 valgrind 下无法出现时,大多数情况下,Memcheck 工具应该都能检测出错误的内存操作。 

4.5. Memcheck doesn't report any errors and I know my program has errors. 
产生上述问题可能有两种原因。 

      首先,默认情况下,valgrind 只会跟踪 top-level 进程,因此,如果你的程序会创建子进程,则默认情况下,子进程 不会被 valgrind 所跟踪。同样的,如果你的程序时通过 shell 脚本、Perl 脚本,或者其他类似的脚本启动的,那么 valgrind 将会跟踪 shell 或 Perl 解析器,或其他类似的东西。 

为了跟踪子进程,需要使用  --trace-children=yes 选项。 

      如果你打算跟踪的进程是由很多进程构成,最好的方式是将输出结构通过网络发送到某处。可以通过指定  --log-socket=127.0.0.1:12345 选项(将输出结果发送到本地 12345 端口)达成此目的。 你可以使用  valgrind-listener 程序建立该端口的监听。 

valgrind-listener 12345 当然,你必须事先启动监听进程才能正常工作。 

      其次,大多数 valgrind 工具的工作模式为,通过替换程序中的某些函数,例如 malloc ,为自定义版本,来达成探测和分析的目的 ,如果你的程序是静态链接的 ,则不会进程这种替换,从而无法进程有效的检测。例如,可能从 Memcheck 输出中看到输出 

All heap blocks were freed -- no leaks are possible 而实际上,你明确知道自己调用了 malloc 。解决办法就是使用  --soname-synonyms=somalloc=NONE 设置,或者在目标程序中避免使用静态链接。 

      还存在另外一种无法进行替换的情况,即使用了另外一种 malloc 库,例如 tcmalloc 或 jemalloc 等。在这种情况下,需要通过指定  --soname-synonyms=somalloc=zzzz 选项(其中 zzzz 为替换用的  malloc 库的 soname),以允许 valgrind 进行相应替换。 

4.6. Why doesn't Memcheck find the array overruns in this program? 

int static[5];int main(void)
{int stack[5];static[5] = 0;stack [5] = 0;return 0;
}
非常不幸的是,Memcheck 无法针对全局数组或栈数组进行边界检查。我们很想做到,但是目前尚未找到一种合理的实现方式,令这种检查与 Memcheck 的工作方式相符,所以,非常抱歉。 
然而,实验工具  SGcheck 能够探测出这种错误。 你可以通过指定  --tool=exp-sgcheck 选项运行 valgrind 进程相关检查,唯一需要明确的是,该工具可能没有 Memcheck 那么健壮。 

5.2. With Memcheck's memory leak detector, what's the difference between "definitely lost", "indirectly lost", "possibly lost", "still reachable", and "suppressed"? 
详细信息可以参见用户手册中的 Memcheck 章节。 
简要说明如下: 

  • "definitely lost" 意味着你的程序一定存在内存泄露;
  • "indirectly lost" 意味着你的程序一定存在内存泄露,并且泄露情况和指针结构相关(例如,如果二叉树的根节点被判定为"definitely lost",则其所有子节点将被判定为"indirectly lost");如果你正确修复了类型为 "definitely lost" 的泄露,那么类型为 "indirectly lost" 的泄露应该会随着消失;
  • "possibly lost" 意味着你的程序一定存在内存泄露,除非你是故意进行着不符合常规的操作,例如将指针指向某个已分配内存块的中间位置。参见用户手册查询一些可能的情况。可以指定 --show-possibly-lost=no 选项屏蔽掉这类报告信息。
  • "still reachable" 意味着你的程序可能是没问题的,但确实没有释放掉一些本可以释放的内存。这种情况是很常见的,并且通常基于合理的理由。 可以通过 --show-reachable=yes 选项控制是否输出相应的报告信息。
  • "suppressed" 意味着有些泄露信息被压制了。在默认的 suppression 文件中可以看到一些 suppression 相关设置。理论上讲,你可以忽略这类错误。

5.4. Is it possible to attach Valgrind to a program that is already running? 
不可以,因为 valgrind 为程序运行使用了完全不同的环境设置,例如采用了不同的内存布局方案等。所以 valgrind 需要在程序启动伊始就进行完全控制。

It is possible to achieve something like this by running your program without any instrumentation (which involves a slow-down of about 5x, less than that of most tools), and then adding instrumentation once you get to a point of interest. Support for this must be provided by the tool, however, and Callgrind is the only tool that currently has such support. See the instructions on the callgrind_control program for details. 


实验输出

[root@Betty ~]#
[root@Betty ~]# valgrind ls -l
==23285== Memcheck, a memory error detector
==23285== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23285== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==23285== Command: ls -l
==23285==
总用量 504
-rw-------. 1 root root 1676 310 2014 anaconda-ks.cfg
...
==23285==
==23285== HEAP SUMMARY:
==23285== in use at exit: 20,296 bytes in 33 blocks
==23285== total heap usage: 266 allocs, 233 frees, 99,073 bytes allocated
==23285==
==23285== LEAK SUMMARY:
==23285== definitely lost: 0 bytes in 0 blocks
==23285== indirectly lost: 0 bytes in 0 blocks
==23285== possibly lost: 0 bytes in 0 blocks
==23285== still reachable: 20,296 bytes in 33 blocks
==23285== suppressed: 0 bytes in 0 blocks
==23285== Rerun with --leak-check=full to see details of leaked memory
==23285==
==23285== For counts of detected and suppressed errors, rerun with: -v
==23285== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
[root@Betty ~]#
[root@Betty ~]#




推荐阅读
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 海马s5近光灯能否直接更换为H7?
    本文主要介绍了海马s5车型的近光灯是否可以直接更换为H7灯泡,并提供了完整的教程下载地址。此外,还详细讲解了DSP功能函数中的数据拷贝、数据填充和浮点数转换为定点数的相关内容。 ... [详细]
  • 本文介绍了使用Spark实现低配版高斯朴素贝叶斯模型的原因和原理。随着数据量的增大,单机上运行高斯朴素贝叶斯模型会变得很慢,因此考虑使用Spark来加速运行。然而,Spark的MLlib并没有实现高斯朴素贝叶斯模型,因此需要自己动手实现。文章还介绍了朴素贝叶斯的原理和公式,并对具有多个特征和类别的模型进行了讨论。最后,作者总结了实现低配版高斯朴素贝叶斯模型的步骤。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文介绍了如何清除Eclipse中SVN用户的设置。首先需要查看使用的SVN接口,然后根据接口类型找到相应的目录并删除相关文件。最后使用SVN更新或提交来应用更改。 ... [详细]
  • IjustinheritedsomewebpageswhichusesMooTools.IneverusedMooTools.NowIneedtoaddsomef ... [详细]
  • JDK源码学习之HashTable(附带面试题)的学习笔记
    本文介绍了JDK源码学习之HashTable(附带面试题)的学习笔记,包括HashTable的定义、数据类型、与HashMap的关系和区别。文章提供了干货,并附带了其他相关主题的学习笔记。 ... [详细]
  • Whatsthedifferencebetweento_aandto_ary?to_a和to_ary有什么区别? ... [详细]
author-avatar
dujiaolianglong
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有