zoukankan      html  css  js  c++  java
  • memwatch的使用

    博主的新Blog地址:http://www.brantchen.com

    欢迎訪问:)


           linux下的測试工具真是少之又少,还不好用,近期试用了memwatch,感觉网上的介绍不太好,所以放在这里跟大家分享 。事实上大部分都是看的帮助,非常多地方翻译得不好还有错,请原谅指出最好看原文。假设转载或引用,请注明我的博客地址,谢谢。

           

    1介绍

    MemWatch Johan Lindh 编写,是一个开放源码 C 语言内存错误检測工具。MemWatch支持 ANSI C,它提供结果日志纪录,能检測双重释放(double-free)、错误释放(erroneous free)、内存泄漏(unfreed memory)、溢出(Overflow)、下溢(Underflow)等等。

     

    1.1 MemWatch的内存处理

    MemWatch将全部分配的内存用0xFE填充,所以,假设你看到错误的数据是用0xFE填充的,那就是你没有初始化数据。例外是calloc(),它会直接把分配的内存用0填充。

    MemWatch将全部已释放的内存用0xFD填充(zapped with 0xFD).假设你发现你使用的数据是用0xFD填充的,那你就使用的是已释放的内存。在这样的情况,注意MemWatch会马上把一个"释放了的块信息"填在释放了的数据前。这个块包含关于内存在哪儿释放的信息,以可读的文本形式存放,格式为"FBI<counter>filename(line)"。如:"FBI<267>test.c(12)".使用FBI会减少free()的速度,所以默认是关闭的。使用mwFreeBufferInfo(1)开启。

    为了帮助跟踪野指针的写情况,MemWatch能提供no-mans-landNML)内存填充。no-mans-land将使用0xFC填充.no-mans-land开启时,MemWatch转变释放的内存为NML填充状态。

     

    1.2初始化和结束处理

    一般来说,在程序中使用MemWatch的功能,须要手动加入mwInit()进行初始化,并用相应的mwTerm ()进行结束处理。

    当然,假设没有手动调用mwInit()MemWatch能自己主动初始化.假设是这样的情形,memwatch会使用atext()注冊mwTerm()用于atexit-queue.对于使用自己主动初始化技术有一个告诫;假设你手动调用atexit()以进行清理工作,memwatch可能在你的程序结束前就终止。为了安全起见,请显式使用mwInit()mwTerm().

    涉及的函数主要有:

    mwInit()   mwTerm()    mwAbort()

     

    1.3 MemWatchI/O操作

    对于一般的操作,MemWatch创建memwatch.log文件。有时,该文件不能被创建;MemWatch会试图创建memwatNN.log文件,NN01~99之间。

    假设你不能使用日志,或者不想使用,也没有问题。仅仅要使用类型为"void func(int c)"的參数调用mwSetOutFunc(),然后全部的输出都会按字节定向到该函数.

    ASSERT或者VERIFY失败时,MemWatch也有Abort/Retry/Ignore处理机制。默认的处理机制没有I/O操作,可是会自己主动中断程序。你能够使用不论什么其它Abort/Retry/Ignore的处理机制,仅仅要以參数"void func(int c)"调用mwSetAriFunc()。后面在1.2使用一节会具体解说。

    涉及的函数主要有:

    mwTrace()          mwPuts()        mwSetOutFunc() mwSetAriFunc()

    mwSetAriAction()   mwAriHandler()  mwBreakOut()

     

    1.4 MemWatchC++的支持

       能够将MemWatch用于C++,可是不推荐这么做。请具体阅读memwatch.h中关于对C++的支持。

     

    2使用

    2.1为自己的程序提供MemWatch功能

    Ø       在要使用MemWatch.c文件里包括头文件"memwatch.h"

    Ø       使用GCC编译(注意:不是链接)自己的程序时,增加-DMEMWATCH -DMW_STDIO
    如:gcc -DMEMWATCH -DMW_STDIO –o test.o
    –c test1.c

     

    2.2使用MemWatch提供的功能

    1在程序中经常使用的MemWatch功能有:

    Ø        mwTRACE( const char* format_string, ... );
    TRACE( const char* format_string, ... );

    Ø        mwASSERT( int, const char*, const char*, int )
    ASSERT( int, const char*, const char*, int )

    Ø        mwVERIFY( int, const char*, const char*, int )
    VERIFY( int, const char*, const char*, int )

    Ø        mwPuts( const char* text )

    Ø        ARI机制(mwSetAriFunc(int (*func)(const char *))
              mwSetAriAction(int action)

              mwAriHandler
    ( const char* cause )

    Ø        mwSetOutFunc(void (*func)(int))

    Ø        mwIsReadAddr(const void *p, unsigned len )

    Ø        mwIsSafeAddr(void *p, unsigned len )

    Ø        mwStatistics( int level )

    Ø        mwBreakOut( const char* cause)

     

    2mwTRACEmwASSERTmwVERIFYmwPuts顾名思义,就不再赘述。仅须要注意的是,Memwatch定义了宏TRACE,   ASSERT VERIFY.假设你已使用同名的宏,memwatch2.61及更高版本号的memwatch不会覆盖你的定义。MemWatch2.61及以后,定义了mwTRACE, mwASSERT mwVERIFY宏,这样,你就能确定使用的是memwatch的宏定义。2.61版本号前的memwatch会覆盖已存在的同名的TRACE, ASSERT VERIFY定义。

    当然,假设你不想使用MemWatch的这几个宏定义,能够定义MW_NOTRACE, MW_NOASSERT MW_NOVERIFY宏,这样MemWatch的宏定义就不起作用了。全部版本号的memwatch都遵照这个规则。

    3ARI机制即程序设置的“Abort, Retry, Ignore选择陷阱。

    mwSetAriFunc

    设置“Abort, Retry, Ignore”发生时的MemWatch调用的函数.当这样设置调用的函数地址时,实际的错误消息不会打印出来,但会作为一个參数进行传递。

    假设參数传递NULLARI处理函数会被再次关闭。当ARI处理函数关闭后, meewatch会自己主动调用有mwSetAriAction()指定的操作。

    正常情况下,失败的ASSERT() or VERIFY()会中断你的程序。但这能够通过mwSetAriFunc()改变,即通过将函数"int myAriFunc(const char *)"传给它实现。你的程序必须询问用户是否中断,重试或者忽略这个陷阱。返回2用于Abort 1用于Retry,或者0对于Ignore。注意retry时,会导致表达式又一次求值.

     MemWatch有个默认的ARI处理器。默认是关闭的,但你能通过调用mwDefaultAri()开启。注意这仍然会中止你的程序除非你定义MEMWATCH_STDIO同意MemWatch使用标准CI/O流。

    同一时候,设置ARI函数也会导致MemWatch不将ARI的错误信息写向标准错误输出,错误字符串而是作为'const char *'參数传递到ARI函数.

    mwSetAriAction

    假设没有ARI处理器被指定,设置默认的ARI返回值。默认是MW_ARI_ABORT

    mwAriHandler

    这是个标准的ARI处理器,假设你喜欢就虽然用。它将错误输出到标准错误输出,并从标准输入获得输入。

    mwSetOutFunc

    将输出转向调用者给出的函数(參数即函数地址)。參数为NULL,表示把输出写入日志文件memwatch.log.

    mwIsReadAddr:

    检查内存是否有读取的权限

    mwIsSafeAddr:

    检查内存是否有读、写的权限

    mwStatistics:

    设置状态搜集器的行为。相应的參数採用宏定义。

    #define MW_STAT_GLOBAL 0       /* 仅搜集全局状态信息 */

    #define MW_STAT_MODULE 1       /* 搜集模块级的状态信息 */

    #define MW_STAT_LINE   2       /* 搜集代码行级的状态信息 */

    #define MW_STAT_DEFAULT 0      /* 默认状态设置 */

    mwBreakOut:

    当某些情况MemWatch认为中断(break into)编译器更好时,就调用这个函数.假设你喜欢使用MemWatch,那么能够在这个函数上设置运行断点。

    其它功能的使用,请參考源码的说明。

     

    2.3分析日志文件

    日志文件memwatch.log中包括的信息主要有下面几点:

    Ø        測试日期

    Ø        状态搜集器的信息

    Ø        使用MemWatch的输出函数或宏(如TRACE等)的信息。

    Ø        MemWatch捕获的错误信息

    Ø        内存使用的全局信息统计,包含四点:1)分配了多少次内存 2)最大内存使用量3)分配的内存总量 4)为释放的内存总数

    MemWatch捕获的错误记录在日志文件里的输出格式例如以下:

    message: <sequence-number> filename(linenumber), information

     

    2.4注意事项

    mwInit()mwTerm()是相应的.所以使用了多少次mwInit(),就须要调用多少次

    mwTerm()用于终止MemWatch.

     

    假设在流程中捕获了程序的异常中断,那么须要调用mwAbort()而不是

    mwTerm()。即使有显示的调用mwTerm()mwAbort()也将终止MemWatch

     

    MemWatch不能确保是线程安全的。假设你碰巧使用Wind32或者你使用了线程,作为2.66,是初步支持线程的。定义WIN32或者MW_PTHREADS以明白支持线程。这会导致一个全局相互排斥变量产生,同一时候当訪问全局内存链时,MemWatch会锁定相互排斥变量,但这远不能证明是线程安全的。

     

    3结论

        MemWatch的使用能够得知,无法用于内核模块。由于MemWatch自身就使用了应用层的接口,而不是内核接口。可是,对于普通的应用层程序,我觉得还是比較实用,而且是开源的,能够自己改动代码实现;它能方便地查找内存泄漏,特别是提供的接口函数简单易懂,学习掌握非常easy,相应用层程序的单元測试会较适用。

     

    博主的新Blog地址:http://www.brantchen.com

    欢迎訪问:)
  • 相关阅读:
    sfs2x 连接 mongodb
    java websocket
    webstorm 4.0 注册码
    解决 sfs2 admin tool 找不到扩展
    window 注册表五大类
    opengl 学习第二日
    java google Protobuf
    扩展 java sencha touch PhonegapPlugin
    sencha touch2 kryonet socket phonegap 通信 作者:围城
    sencha touch2 layout 笔记
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4063258.html
Copyright © 2011-2022 走看看