﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-程序人生-文章分类-linux_bug_tool</title><link>http://www.cppblog.com/liu1061/category/7482.html</link><description>生活和工作都要充满激情,否则你无法体会到淋漓尽致的快乐与痛苦</description><language>zh-cn</language><lastBuildDate>Tue, 01 Jul 2008 04:38:22 GMT</lastBuildDate><pubDate>Tue, 01 Jul 2008 04:38:22 GMT</pubDate><ttl>60</ttl><item><title>Memwatch Tool </title><link>http://www.cppblog.com/liu1061/articles/55010.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Tue, 01 Jul 2008 02:12:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/55010.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/55010.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/55010.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/55010.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/55010.html</trackback:ping><description><![CDATA[<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">1 介绍<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemWatch由 Johan&nbsp; Lindh 编写，是一个开放源代码 C 语言内存错误检测工具。MemWatch支持 ANSI C，它提供结果<a onclick="javascript:tagshow(event, '%C8%D5%D6%BE');" href="javascript:;" target=_self><u><strong><font color=#0000ff>日志</font></strong></u></a>纪录，能检测双重释放（double-free）、错误释放（erroneous free）、内存泄漏（unfreed memory）、溢出(Overflow)、下溢(Underflow)等等。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">1.1 MemWatch的内存处理<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemWatch将所有分配的内存用0xFE填充，所以，如果你看到错误的数据是用0xFE填充的，那就是你没有初始化数据。例外是calloc()，它会直接把分配的内存用0填充。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemWatch将所有已释放的内存用0xFD填充(zapped with 0xFD).如果你发现你使用的数据是用0xFD填充的，那你就使用的是已释放的内存。在这种情况，注意MemWatch会立即把一个"释放了的块信息"填在释放了的数据前。这个块包括关于内存在哪儿释放的信息，以可读的文本形式存放，格式为"FBI&lt;counter&gt;filename(line)"。如:"FBI&lt;267&gt;test.c(12)".使用FBI会降低free()的速度，所以默认是关闭的。使用mwFreeBufferInfo(1)开启。 </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了帮助跟踪野指针的写情况，MemWatch能提供no-mans-land（NML）内存填充。no-mans-land将使用0xFC填充.当no-mans-land开启时，MemWatch转变释放的内存为NML填充状态。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">1.2初始化和结束处理<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一般来说，在程序中使用MemWatch的功能，需要手动添加mwInit()进行初始化，并用对应的mwTerm ()进行结束处理。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然，如果没有手动调用mwInit()，MemWatch能自动初始化.如果是这种情形，memwatch会使用atext()注册mwTerm()用于atexit-queue. 对于使用自动初始化<a onclick="javascript:tagshow(event, '%BC%BC%CA%F5');" href="javascript:;" target=_self><u><strong><font color=#0000ff>技术</font></strong></u></a>有一个告诫;如果你手动调用atexit()以进行清理<a onclick="javascript:tagshow(event, '%B9%A4%D7%F7');" href="javascript:;" target=_self><u><strong><font color=#0000ff>工作</font></strong></u></a>，memwatch可能在你的程序结束前就终止。为了安全起见，请显式使用mwInit()和mwTerm().</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 涉及的函数主要有：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwInit()&nbsp;&nbsp;&nbsp; mwTerm()&nbsp;&nbsp;&nbsp; mwAbort()</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">1.3 MemWatch的I/O 操作<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于一般的操作，MemWatch创建memwatch.log文件。有时，该文件不能被创建;MemWatch会试图创建memwatNN.log文件，NN在01~99之间。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果你不能使用日志，或者不想使用，也没有问题。只要使用类型为"void func(int c)"的参数调用mwSetOutFunc()，然后所有的输出都会按字节定向到该函数.</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当ASSERT或者VERIFY失败时，MemWatch也有Abort/Retry/Ignore处理机制。默认的处理机制没有I/O操作，但是会自动中断程序。你可以使用任何其他Abort/Retry/Ignore的处理机制,只要以参数"void func(int c)"调用mwSetAriFunc()。后面在1.2使用一节会详细讲解。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 涉及的函数主要有：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwTrace()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwPuts()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwSetOutFunc()&nbsp; mwSetAriFunc()</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwSetAriAction()&nbsp;&nbsp;&nbsp; mwAriHandler()&nbsp; mwBreakOut() </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">1.4 MemWatch对C++的支持<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以将MemWatch用于C++,但是不推荐这么做。请详细阅读memwatch.h中关于对C++的支持。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">2 使用<br>2.1 为自己的程序提供MemWatch功能<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在要使用MemWatch的.c文件中包含头文件"memwatch.h"</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用GCC编译（注意：不是链接）自己的程序时，加入-DMEMWATCH -DMW_STDIO<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如：gcc -DMEMWATCH -DMW_STDIO &#8211;o test.o &#8211;c&nbsp; test1.c </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">2.2 使用MemWatch提供的功能<br>1）在程序中常用的MemWatch功能有：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwTRACE ( const char* format_string, ... );<br>或TRACE ( const char* format_string, ... );</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwASSERT ( int, const char*, const char*, int )<br>或ASSERT ( int, const char*, const char*, int )</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwVERIFY ( int, const char*, const char*, int )<br>或VERIFY ( int, const char*, const char*, int )</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwPuts ( const char* text )</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ARI机制（ mwSetAriFunc(int (*func)(const char *))，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwSetAriAction(int action)，<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwAriHandler ( const char* cause )）</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwSetOutFunc (void (*func)(int))</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwIsReadAddr(const void *p, unsigned len )</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwIsSafeAddr(void *p, unsigned len )</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwStatistics ( int level )</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwBreakOut ( const char* cause)</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2）mwTRACE，mwASSERT，mwVERIFY和mwPuts顾名思义，就不再赘述。仅需要注意的是，Memwatch定义了宏TRACE,&nbsp;&nbsp;&nbsp; ASSERT 和 VERIFY.如果你已使用同名的宏,memwatch2.61及更高版本的memwatch不会覆盖你的定义。MemWatch2.61及以后，定义了mwTRACE, mwASSERT 和 mwVERIFY宏，这样，你就能确定使用的是memwatch的宏定义。2.61版本前的memwatch会覆盖已存在的同名的TRACE, ASSERT 和 VERIFY定义。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当然，如果你不想使用MemWatch的这几个宏定义，可以定义MW_NOTRACE, MW_NOASSERT 和 MW_NOVERIFY宏，这样MemWatch的宏定义就不起作用了。所有版本的memwatch都遵照这个规则。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3）ARI机制即程序设置的&#8220;Abort, Retry, Ignore选择陷阱。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwSetAriFunc：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 设置&#8220;Abort, Retry, Ignore&#8221;发生时的MemWatch调用的函数.当这样设置调用的函数地址时，实际的错误消息不会打印出来，但会作为一个参数进行传递。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果参数传递NULL，ARI处理函数会被再次关闭。当ARI处理函数关闭后， meewatch会自动调用有mwSetAriAction()指定的操作。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 正常情况下，失败的ASSERT() or VERIFY()会中断你的程序。但这可以通过mwSetAriFunc()改变，即通过将函数"int myAriFunc(const char *)"传给它实现。你的程序必须询问用户是否中断，重试或者忽略这个陷阱。返回2用于Abort， 1用于Retry，或者0对于Ignore。注意retry时，会导致表达式重新求值.</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemWatch有个默认的ARI处理器。默认是关闭的，但你能通过调用mwDefaultAri()开启。注意这仍然会中止你的程序除非你定义MEMWATCH_STDIO允许MemWatch使用标准C的I/O流。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 同时，设置ARI函数也会导致MemWatch不将ARI的错误信息写向标准错误输出，错误字符串而是作为'const char *'参数传递到ARI函数.</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwSetAriAction：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果没有ARI处理器被指定，设置默认的ARI返回值。默认是MW_ARI_ABORT</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwAriHandler：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这是个标准的ARI处理器，如果你喜欢就尽管用。它将错误输出到标准错误输出，并从标准输入获得输入。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwSetOutFunc：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 将输出转向调用者给出的函数(参数即函数地址)。参数为NULL，表示把输出写入日志文件memwatch.log.</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwIsReadAddr:</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 检查内存是否有读取的权限</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwIsSafeAddr:</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 检查内存是否有读、写的权限</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwStatistics:</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 设置状态搜集器的行为。对应的参数采用宏定义。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">#define MW_STAT_GLOBAL&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 仅搜集全局状态信息 */</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">#define MW_STAT_MODULE&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 搜集模块级的状态信息 */</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">#define MW_STAT_LINE&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 搜集代码行级的状态信息 */</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">#define MW_STAT_DEFAULT 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 默认状态设置 */</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">mwBreakOut: </p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 当某些情况MemWatch觉得中断(break into)编译器更好时，就调用这个函数.如果你喜欢使用MemWatch,那么可以在这个函数上设置执行断点。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a onclick="javascript:tagshow(event, '%C6%E4%CB%FB');" href="javascript:;" target=_self><u><strong><font color=#0000ff>其他</font></strong></u></a>功能的使用，请参考源代码的说明。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">2.3分析日志文件<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 日志文件memwatch.log中包含的信息主要有以下几点：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试日期</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 状态搜集器的信息</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用MemWatch的输出函数或宏（如TRACE等）的信息。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemWatch捕获的错误信息</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内存使用的全局信息统计，包括四点：1）分配了多少次内存 2）最大内存使用量3）分配的内存总量 4）为释放的内存总数</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemWatch捕获的错误记录在日志文件中的输出格式如下：</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">message: &lt;sequence-number&gt; filename(linenumber), information</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">2.4 注意事项<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwInit()和mwTerm()是对应的.所以使用了多少次mwInit()，就需要调用多少次</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwTerm()用于终止MemWatch.</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果在流程中捕获了程序的异常中断，那么需要调用mwAbort()而不是</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mwTerm()。即使有显示的调用mwTerm()，mwAbort()也将终止MemWatch。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MemWatch不能确保是线程安全的。如果你碰巧使用Wind32或者你使用了线程，作为2.66，是初步支持线程的。定义WIN32或者MW_PTHREADS以明确支持线程。这会导致一个全局互斥变量产生，同时当访问全局内存链时，MemWatch会锁定互斥变量，但这远不能证明是线程安全的。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">3 结论<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 从MemWatch的使用可以得知，无法用于内核模块。因为MemWatch自身就使用了应用层的接口，而不是内核接口。但是，对于普通的应用层程序，我认为还是比较有用，并且是开源的，可以自己修改代码实现；它能方便地查找内存泄漏，特别是提供的接口函数简单易懂，<a onclick="javascript:tagshow(event, '%D1%A7%CF%B0');" href="javascript:;" target=_self><u><strong><font color=#0000ff>学习</font></strong></u></a>掌握很容易，对应用层程序的<a onclick="javascript:tagshow(event, '%B5%A5%D4%AA%B2%E2%CA%D4');" href="javascript:;" target=_self><u><strong><font color=#0000ff>单元测试</font></strong></u></a>会较适用。</p>
<img src ="http://www.cppblog.com/liu1061/aggbug/55010.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-07-01 10:12 <a href="http://www.cppblog.com/liu1061/articles/55010.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux 内存调试工具- Valgrind 使用初探</title><link>http://www.cppblog.com/liu1061/articles/55007.html</link><dc:creator>T.S Liu</dc:creator><author>T.S Liu</author><pubDate>Tue, 01 Jul 2008 02:02:00 GMT</pubDate><guid>http://www.cppblog.com/liu1061/articles/55007.html</guid><wfw:comment>http://www.cppblog.com/liu1061/comments/55007.html</wfw:comment><comments>http://www.cppblog.com/liu1061/articles/55007.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/liu1061/comments/commentRss/55007.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/liu1061/services/trackbacks/55007.html</trackback:ping><description><![CDATA[<span style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">Valgrind 是在linux系统下开发应用程序时用于调试内存问题的工具。它尤其擅长发现内存管理的问题，它可以检查程序运行时的内存泄漏问题。</span>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp; 它的官方网址是 <a href="http://www.valgrind.org/">http://www.valgrind.org/</a></p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp; 下载最新版本的Valgrind，目前是3.2.0。 wget <a href="http://www.valgrind.org/downloads/valkyrie-1.2.0.tar.bz2">http://www.valgrind.org/downloads/valkyrie-1.2.0.tar.bz2</a></p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp; 执行常规的安装步骤：./confgure &amp;&amp; make &amp;&amp; make install。注意： 系统必须安装QT的开发包。即便这样在make 时还是出现qplatformdefs.h这个文件找不到的情况，导致make失败。查找系统中的qplatformdefs.h 之后，发现没有存在于qt的标准头文件目录/usr/lib/qt-3.3/include。如是将/usr/lib/qt-3.3/mkspecs/linux-g++/ 目录下该头文件复制标准头文件目录，重新make ，后面一切OK。</p>
<pre>初次使用</pre>
<pre>    编译如下代码:  gcc -Wall example.c -g -o example </pre>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">
<table align=center>
    <tbody>
        <tr>
            <td style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">
            <pre>#include &lt;stdlib.h&gt;
            void f(void)
            {
            int* x = malloc(10 * sizeof(int));
            x[10] = 0;        // problem 1: heap block overrun
            }                    // problem 2: memory leak -- x not freed
            int main(void)
            {
            f();
            return 0;
            }</pre>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp;&nbsp;&nbsp; 注意：gcc 的-g 选项让Valgrind调试输出时指出相应信息的代码所在的行号。</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;
<table align=center>
    <tbody>
        <tr>
            <td style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">valgrind --tool=memcheck --leak-check=yes&nbsp;./example</td>
        </tr>
    </tbody>
</table>
</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">
<table align=center>
    <tbody>
        <tr>
            <td style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">==6742== Memcheck, a memory error detector for x86-linux.<br>==6742== Copyright (C) 2002-2004, and GNU GPL'd, by Julian Seward et al.<br>==6742== Using valgrind-2.2.0, a program supervision framework for x86-linux.<br>==6742== Copyright (C) 2000-2004, and GNU GPL'd, by Julian Seward et al.<br>==6742== For more details, rerun with: -v<br>==6742== <br>==6742== Invalid write of size 4<br>==6742==&nbsp;&nbsp;&nbsp; at 0x8048384: f (example.c:6)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x80483AC: main (example.c:12)<br>==6742==&nbsp; Address 0x1B908050 is 0 bytes after a block of size 40 alloc'd<br>==6742==&nbsp;&nbsp;&nbsp; at 0x1B904984: malloc (vg_replace_malloc.c:131)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x8048377: f (example.c:5)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x80483AC: main (example.c:12)<br>==6742== <br>==6742== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 12 from 1)<br>==6742== malloc/free: in use at exit: 40 bytes in 1 blocks.<br>==6742== malloc/free: 1 allocs, 0 frees, 40 bytes allocated.<br>==6742== For counts of detected errors, rerun with: -v<br>==6742== searching for pointers to 1 not-freed blocks.<br>==6742== checked 1360800 bytes.<br>==6742== <br>==6742== <br>==6742== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1<br>==6742==&nbsp;&nbsp;&nbsp; at 0x1B904984: malloc (vg_replace_malloc.c:131)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x8048377: f (example.c:5)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x80483AC: main (example.c:12)<br>==6742== <br>==6742== LEAK SUMMARY:<br>==6742==&nbsp;&nbsp;&nbsp; definitely lost: 40 bytes in 1 blocks.<br>==6742==&nbsp;&nbsp;&nbsp; possibly lost:&nbsp;&nbsp; 0 bytes in 0 blocks.<br>==6742==&nbsp;&nbsp;&nbsp; still reachable: 0 bytes in 0 blocks.<br>==6742==&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; suppressed: 0 bytes in 0 blocks.<br>==6742== Reachable blocks (those to which a pointer was found) are not shown.<br>==6742== To see them, rerun with: --show-reachable=yes</td>
        </tr>
    </tbody>
</table>
</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">&nbsp;&nbsp; 上面的C程序存在两个错误：1. 数组下标越界；2. 分配的内存没有释放，存在内存泄露的问题。对于错误1，看Valgrind的调试信息片断
<table align=center>
    <tbody>
        <tr>
            <td style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">==6742== Invalid write of size 4<br>==6742==&nbsp;&nbsp;&nbsp; at 0x8048384: f (example.c:6)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x80483AC: main (example.c:12)<br>==6742==&nbsp; Address 0x1B908050 is 0 bytes after a block of size 40 alloc'd<br>==6742==&nbsp;&nbsp;&nbsp; at 0x1B904984: malloc (vg_replace_malloc.c:131)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x8048377: f (example.c:5)</td>
        </tr>
    </tbody>
</table>
</p>
<p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">对于错误2，看这个
<table align=center>
    <tbody>
        <tr>
            <td style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">
            <p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">==6742== malloc/free: 1 allocs, 0 frees, 40 bytes allocated.</p>
            <p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">......</p>
            <p style="FONT-SIZE: 10pt; FONT-FAMILY: courier new">==6742== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1<br>==6742==&nbsp;&nbsp;&nbsp; at 0x1B904984: malloc (vg_replace_malloc.c:131)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x8048377: f (example.c:5)<br>==6742==&nbsp;&nbsp;&nbsp; by 0x80483AC: main (example.c:12)</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<img src ="http://www.cppblog.com/liu1061/aggbug/55007.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/liu1061/" target="_blank">T.S Liu</a> 2008-07-01 10:02 <a href="http://www.cppblog.com/liu1061/articles/55007.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>