天天看点

点评五款用于 Linux 编程的内存调试器点评五款用于 Linux 编程的内存调试器

点评五款用于 Linux 编程的内存调试器点评五款用于 Linux 编程的内存调试器

作为一个程序员,我知道我肯定会犯错误——怎么可能不犯错!程序员也是人啊。有的错误能在编码过程中及时发现,而有些却得等到软件测试了才能显露出来。然而,还有一类错误并不能在这两个阶段被解决,这就导致软件不能正常运行,甚至是提前终止。

幸运的是,现在有一些编程工具能够帮你在软件程序中找到这些和内存相关的错误。在这些工具集中,我评估了五款支持 linux 的、流行的、自由开源的内存调试器: dmalloc 、 electric fence 、 memcheck 、 memwatch 以及 mtrace 。在日常编码中,我已经用过这五个调试器了,所以这些评估是建立在我的实际体验之上的。

<a></a>

开发者:gray watson

评估版本:5.5.2

支持的 linux 版本:所有种类

许可: cc 3.0

dmalloc 是 gray watson 开发的一款内存调试工具。它是作为库来实现的,封装了标准内存管理函数如<code>malloc()</code> , <code>calloc() </code>,<code> free()</code>等,使程序员得以检测出有问题的代码。

点评五款用于 Linux 编程的内存调试器点评五款用于 Linux 编程的内存调试器

dmalloc

dmalloc 最大的优点就是高度可配置性。比如说,你可以配置它以支持 c++ 程序和多线程应用。 dmalloc 还提供一个有用的功能:运行时可配置,这表示在 dmalloc 执行时,可以轻易地启用或者禁用它提供的一些特性。

跟 mtrace 一样, dmalloc 需要程序员改动他们的源代码。比如说你可以(也是必须的)添加头文件<code>dmalloc.h</code>,工具就能汇报产生问题的调用的文件或行号。这个功能非常有用,因为它节省了调试的时间。

除此之外,还需要在编译你的程序时,把 dmalloc 库(编译 dmalloc 源码包时产生的)链接进去。

dmalloc 真正的优势在于它的可配置选项。而且高度可移植,曾经成功移植到多种操作系统如 aix 、 bsd/os 、 dg/ux 、 free/net/openbsd 、 gnu/hurd 、 hpux 、 irix 、 linux 、 ms-dog 、 next 、 osf 、 sco 、 solaris 、 sunos 、 ultrix 、 unixware 甚至 unicos(运行在 cray t3e 主机上)。虽然使用 dmalloc 需要学习许多知识,但是它所提供的特性值得为之付出。

开发者:bruce perens

评估版本:2.2.3

许可:gpl v2

点评五款用于 Linux 编程的内存调试器点评五款用于 Linux 编程的内存调试器

electric fence

我喜欢 electric fence 的首要一点是它不同于 memwatch 、 dmalloc 和 mtrace ,不需要对你的源码做任何的改动,你只需要在编译的时候把它的库链接进你的程序即可。

其次, electric fence 的实现保证了产生越界访问的第一个指令就会引起段错误。这比在后面再发现问题要好多了。

不管是否有检测出错误, electric fence 都会在输出产生版权信息。这一点非常有用,由此可以确定你所运行的程序已经启用了 electric fence 。

另一方面,我对 electric fence 真正念念不忘的是它检测内存泄漏的能力。内存泄漏是 c/c++ 软件最常见也是最不容易发现的问题之一。不过, electric fence 不能检测出栈溢出,而且也不是线程安全的。

由于 electric fence 会在用户分配内存区的前后分配禁止访问的虚拟内存页,如果你过多的进行动态内存分配,将会导致你的程序消耗大量的额外内存。

最后一点,尽管 electric fence 能检测出大部分的缓冲区溢出,有一个例外是,如果所申请的缓冲区大小不是系统字长的倍数,这时候溢出(即使只有几个字节)就不能被检测出来。

尽管局限性较大, electric fence 的易用性仍然是加分项。只要链接一次程序, electric fence 就可以在监测出内存相关问题的时候报警。不过,如同前面所说, electric fence 需要配合像 gdb 这样的源码调试器使用。

评估版本:3.10.1

支持的 linux 发行版:所有种类

许可:gpl

memcheck ,一款内存错误检测器,是其中最受欢迎的工具。它能够检测出如内存泄漏、无效的内存访问、未定义变量的使用以及堆内存分配和释放相关的问题等诸多问题。

同其它所有 valgrind 工具一样, memcheck 也是命令行程序。它的操作非常简单:通常我们会使用诸如 <code>prog arg1 arg2</code> 格式的命令来运行程序,而 memcheck 只要求你多加几个值即可,如 <code>valgrind --leak-check=full prog arg1 arg2</code> 。

点评五款用于 Linux 编程的内存调试器点评五款用于 Linux 编程的内存调试器

memcheck

(注意:因为 memcheck 是 valgrind 的默认工具,所以在命令行执行命令时无需提及 memcheck。但是,需要在编译程序之初带上 <code>-g</code> 参数选项,这一步会添加调试信息,使得 memcheck 的错误信息会包含正确的行号。)

我真正倾心于 memcheck 的是它提供了很多命令行选项(如上所述的<code>--leak-check</code>选项),如此不仅能控制工具运转还可以控制它的输出。

举个例子,可以开启<code>--track-origins</code>选项,以查看程序源码中未初始化的数据;可以开启<code>--show-mismatched-frees</code>选项让 memcheck 匹配内存的分配和释放技术。对于 c 语言所写的代码, memcheck 会确保只能使用<code>free()</code>函数来释放内存,<code>malloc()</code>函数来申请内存。而对 c++ 所写的源码, memcheck 会检查是否使用了<code>delete</code>或<code>delete[]</code>操作符来释放内存,以及<code>new</code>或者<code>new[]</code>来申请内存。

memcheck 最好的特点,尤其是对于初学者来说,是它会给用户建议使用哪个命令行选项能让输出更加有意义。比如说,如果你不使用基本的<code>--leak-check</code>选项, memcheck 会在输出时给出建议:“使用 --leak-check=full 重新运行以查看更多泄漏内存细节”。如果程序有未初始化的变量, memcheck 会产生信息:“使用 --track-origins=yes 以查看未初始化变量的定位”。

无论是对于初学者还是那些需要高级特性的人来说, memcheck 都是一款便捷的内存调试工具。如果你仅需要基本调试和错误检查, memcheck 会非常容易上手。而当你想要使用像抑制文件或者监控指令这样的特性,就需要花一些功夫学习了。

开发者:johan lindh

评估版本:2.71

许可:gnu gpl

memwatch 支持用 c 语言所编写的程序。也可以在 c++ 程序中使用它,但是这种做法并不提倡(由 memwatch 源码包随附的 q&amp;a 文件中可知)。

这个版本添加了<code>ulong_long_max</code>以区分 32 位和 64 位程序。

跟 dmalloc 一样, memwatch 也有优秀的文档资料。参考 using 文件,可以学习如何使用 memwatch ,可以了解 memwatch 是如何初始化、如何清理以及如何进行 i/o 操作,等等。还有一个 faq 文件,旨在帮助用户解决使用过程遇到的一般问题。最后还有一个<code>test.c</code>文件提供工作案例参考。

点评五款用于 Linux 编程的内存调试器点评五款用于 Linux 编程的内存调试器

memwatch

不同于 mtrace , memwatch 产生的日志文件(通常是<code>memwatch.log</code>)是人类可阅读的格式。而且, memwatch 每次运行时总会把内存调试结果拼接到输出该文件的末尾。如此便可在需要之时轻松查看之前的输出信息。

另一个我喜欢的优点是 memwatch 还提供了在源码中获取其输出信息的方式,你可以获取信息,然后任由你进行处理(参考 memwatch 源码中的<code>mwsetoutfunc()</code>函数获取更多有关的信息)。

跟 mtrace 和 dmalloc 一样, memwatch 也需要你往你的源文件里增加代码:你需要把<code>memwatch.h</code>这个头文件包含进你的代码。而且,编译程序的时候,你需要连同<code>memwatch.c</code>一块编译;或者你可以把已经编译好的目标模块包含起来,然后在命令行定义<code>memwatch</code>和<code>mw_stdio</code>变量。不用说,想要在输出中定位行号, -g 编译器选项也少不了。

此外, memwatch 缺少一些特性。比如 memwatch 不能检测出对一块已经被释放的内存进行写入操作,或是在分配的内存块之外的进行读取操作。而且, memwatch 也不是线程安全的。还有一点,正如我在开始时指出,在 c++ 程序上运行 memwatch 的结果是不能预料的。

memcheck 可以检测很多内存相关的问题,在处理 c 程序时是非常便捷的调试工具。因为源码小巧,所以可以从中了解 memcheck 如何运转,有需要的话可以调试它,甚至可以根据自身需求扩展升级它的功能。

开发者: roland mcgrath 和 ulrich drepper

评估版本: 2.21

点评五款用于 Linux 编程的内存调试器点评五款用于 Linux 编程的内存调试器

mtrace

mtrace 实际上是实现了一个名为<code>mtrace()</code>的函数,它可以跟踪程序中所有 malloc/free 调用,并在用户指定的文件中记录相关信息。文件以一种机器可读的格式记录数据,所以有一个 perl 脚本——同样命名为 mtrace ——用来把文件转换并为人类可读格式。

mtrace 最好的地方是它非常简单易学。你只需要了解在你的源码中如何以及何处添加 <code>mtrace()</code> 及对应的<code>muntrace()</code> 函数,还有如何使用 mtrace 的 perl 脚本。后者非常简单,只需要运行指令<code>mtrace &lt;program-executable&gt; &lt;log-file-generated-upon-program-execution&gt;</code>(例子见开头截图最后一条指令)。

mtrace 另外一个优点是它的可伸缩性,这体现在不仅可以使用它来调试完整的程序,还可以使用它来检测程序中独立模块的内存泄漏。只需在每个模块里调用<code>mtrace()</code>和<code>muntrace()</code>即可。

使用 mtrace ,你需要掌握 linux 环境变量的基本知识,因为在程序执行之前,需要把用户把环境变量<code>malloc_trace</code>的值设为指定的文件(<code>mtrace()</code>函数将会记录全部信息到其中)路径。

不言自明,我在此讨论的每款内存调试器都有其优点和局限。所以,哪一款适合你取决于你所需要的特性,虽然有时候容易安装和使用也是一个决定因素。

要想捕获软件程序中的内存泄漏, mtrace 最适合不过了。它还可以节省时间。由于 linux 系统已经预装了此工具,对于不能联网或者不可以下载第三方调试调试工具的情况, mtrace 也是极有助益的。

另一方面,相比 mtrace , dmalloc 不仅能检测更多错误类型,还提供更多特性,比如运行时可配置、 gdb 集成。而且, dmalloc 不像这里所说的其它工具,它是线程安全的。更不用说它的详细资料了,这让 dmalloc 成为初学者的理想选择。

虽然 memwatch 的资料比 dmalloc 的更加丰富,而且还能检测更多的错误种类,但是你只能在 c 语言写就的程序中使用它。一个让 memwatch 脱颖而出的特性是它允许在你的程序源码中处理它的输出,这对于想要定制输出格式来说是非常有用的。

如果改动程序源码非你所愿,那么使用 electric fence 吧。不过,请记住, electric fence 只能检测两种错误类型,而此二者均非内存泄漏。还有就是,需要基本了解 gdb 以最大化发挥这款内存调试工具的作用。

memcheck 可能是其中综合性最好的了。相比这里提及的其它工具,它能检测更多的错误类型,提供更多的特性,而且不需要你的源码做任何改动。但请注意,基本功能并不难上手,但是想要使用它的高级特性,就必须学习相关的专业知识了。

本文来自云栖社区合作伙伴“linux中国”

原文发布时间为:2013-04-02.

继续阅读