热门标签 | 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 ~]#




推荐阅读
  • 在Cisco IOS XR系统中,存在提供服务的服务器和使用这些服务的客户端。本文深入探讨了进程与线程状态转换机制,分析了其在系统性能优化中的关键作用,并提出了改进措施,以提高系统的响应速度和资源利用率。通过详细研究状态转换的各个环节,本文为开发人员和系统管理员提供了实用的指导,旨在提升整体系统效率和稳定性。 ... [详细]
  • 解决Only fullscreen opaque activities can request orientation错误的方法
    本文介绍了在使用PictureSelectorLight第三方框架时遇到的Only fullscreen opaque activities can request orientation错误,并提供了一种有效的解决方案。 ... [详细]
  • 本文深入解析了 FCEUX 源码,并详细介绍了两种制作 DEB 包的方法及其技术细节。首先,DEB 包通常由两部分组成:控制信息(位于 DEBIAN 目录)和安装内容(模拟目录)。通过解压现有的 DEB 包,可以查看其内部结构,进而理解其工作原理。具体操作包括将安装内容释放到指定目录中,以便进行进一步的修改和定制。此外,文章还探讨了如何修改现有的 DEB 包,以满足特定需求,提供了实用的步骤和技巧。 ... [详细]
  • 本文深入探讨了MDK链接脚本的应用与优化技巧。首先,文章介绍了链接脚本的基本概念及其在嵌入式系统开发中的重要性。接着,通过具体实例详细分析了链接脚本的结构和功能,特别是在程序在FLASH中运行时,如何优化链接脚本以提高系统性能。此外,文章还讨论了无需将程序加载到SRAM中的技术细节,为开发者提供了实用的参考和指导。 ... [详细]
  • 在 CentOS 6.7 系统维护中,常用的巡检命令包括:`uname -a` 用于查看内核、操作系统和 CPU 信息;`head -n 1 /etc/issue` 用于查看操作系统的版本;`cat /proc/cpuinfo` 用于获取详细的 CPU 信息;`hostname` 用于显示当前主机名;`ls` 命令则用于列出目录内容。这些命令可以帮助系统管理员快速了解系统的运行状态和配置信息,确保系统的稳定性和安全性。 ... [详细]
  • 为了在Hadoop 2.7.2中实现对Snappy压缩和解压功能的原生支持,本文详细介绍了如何重新编译Hadoop源代码,并优化其Native编译过程。通过这一优化,可以显著提升数据处理的效率和性能。此外,还探讨了编译过程中可能遇到的问题及其解决方案,为用户提供了一套完整的操作指南。 ... [详细]
  • PHP预处理常量详解:如何定义与使用常量 ... [详细]
  • Android中将独立SO库封装进JAR包并实现SO库的加载与调用
    在Android开发中,将独立的SO库封装进JAR包并实现其加载与调用是一个常见的需求。本文详细介绍了如何将SO库嵌入到JAR包中,并确保在外部应用调用该JAR包时能够正确加载和使用这些SO库。通过这种方式,开发者可以更方便地管理和分发包含原生代码的库文件,提高开发效率和代码复用性。文章还探讨了常见的问题及其解决方案,帮助开发者避免在实际应用中遇到的坑。 ... [详细]
  • 深入解析零拷贝技术(Zerocopy)及其应用优势
    零拷贝技术(Zero-copy)是Netty框架中的一个关键特性,其核心在于减少数据在操作系统内核与用户空间之间的传输次数。通过避免不必要的内存复制操作,零拷贝显著提高了数据传输的效率和性能。本文将深入探讨零拷贝的工作原理及其在实际应用中的优势,包括降低CPU负载、减少内存带宽消耗以及提高系统吞吐量等方面。 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • 本文详细介绍了在Linux系统上编译安装MySQL 5.5源码的步骤。首先,通过Yum安装必要的依赖软件包,如GCC、GCC-C++等,确保编译环境的完备。接着,下载并解压MySQL 5.5的源码包,配置编译选项,进行编译和安装。最后,完成安装后,进行基本的配置和启动测试,确保MySQL服务正常运行。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
  • 在数据库事务处理中,InnoDB 存储引擎提供了多种隔离级别,其中 READ COMMITTED 和 REPEATABLE READ 是两个常用的选项。本文详细对比了这两种隔离级别的特点和差异,不仅从理论角度分析了它们对“脏读”和“幻读”的处理方式,还结合实际应用场景探讨了它们在并发控制和性能表现上的不同。特别关注了行锁机制在不同隔离级别下的行为,为开发者选择合适的隔离级别提供了参考。 ... [详细]
  • 本文深入探讨了RecyclerView的缓存与视图复用机制,详细解析了不同类型的缓存及其功能。首先,介绍了屏幕内ViewHolder的Scrap缓存,这是一种最轻量级的缓存方式,旨在提高滚动性能并减少不必要的视图创建。通过分析其设计原理,揭示了Scrap缓存为何能有效提升用户体验。此外,还讨论了其他类型的缓存机制,如RecycledViewPool和ViewCacheExtension,进一步优化了视图复用效率。 ... [详细]
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社区 版权所有