博主的新Blog地址:http://www.brantchen.comlinux
欢迎訪问:)
linux下的測试工具真是少之又少,还很差用,近期试用了memwatch,感受网上的介绍不太好,因此放在这里跟你们分享 。事实上大部分都是看的帮助,很是多地方翻译得很差还有错,请原谅指出最好看原文。假设转载或引用,请注明个人博客地址,谢谢。安全
MemWatch由 Johan Lindh 编写,是一个开放源码 C 语言内存错误检測工具。MemWatch支持 ANSI C,它提供结果日志纪录,能检測双重释放(double-free)、错误释放(erroneous free)、内存泄漏(unfreed memory)、溢出(Overflow)、下溢(Underflow)等等。app
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-land(NML)内存填充。no-mans-land将使用0xFC填充.当no-mans-land开启时,MemWatch转变释放的内存为NML填充状态。学习
通常来讲,在程序中使用MemWatch的功能,需要手动加入mwInit()进行初始化,并用相应的mwTerm ()进行结束处理。spa
固然,假设没有手动调用mwInit(),MemWatch能本身主动初始化.假设是这样的情形,memwatch会使用atext()注冊mwTerm()用于atexit-queue.对于使用本身主动初始化技术有一个告诫;假设你手动调用atexit()以进行清理工做,memwatch可能在你的程序结束前就终止。为了安全起见,请显式使用mwInit()和mwTerm().线程
涉及的函数主要有:翻译
mwInit() mwTerm() mwAbort()指针
对于通常的操做,MemWatch建立memwatch.log文件。有时,该文件不能被建立;MemWatch会试图建立memwatNN.log文件,NN在01~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()
可以将MemWatch用于C++,但是不推荐这么作。请具体阅读memwatch.h中关于对C++的支持。
Ø
在要使用MemWatch的.c文件里包括头文件"memwatch.h"
Ø
使用GCC编译(注意:不是连接)本身的程序时,增长-DMEMWATCH -DMW_STDIO
如:gcc -DMEMWATCH -DMW_STDIO –o test.o
–c test1.c
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)
2)mwTRACE,mwASSERT,mwVERIFY和mwPuts顾名思义,就再也不赘述。仅需要注意的是,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都遵守这个规则。
3)ARI机制即程序设置的“Abort, Retry, Ignore选择陷阱。
mwSetAriFunc:
设置“Abort, Retry, Ignore”发生时的MemWatch调用的函数.当这样设置调用的函数地址时,实际的错误消息不会打印出来,但会做为一个參数进行传递。
假设參数传递NULL,ARI处理函数会被再次关闭。当ARI处理函数关闭后, meewatch会本身主动调用有mwSetAriAction()指定的操做。
正常状况下,失败的ASSERT() or VERIFY()会中断你的程序。但这可以经过mwSetAriFunc()改变,即经过将函数"int myAriFunc(const char *)"传给它实现。你的程序必须询问用户是否中断,重试或者忽略这个陷阱。返回2用于Abort, 1用于Retry,或者0对于Ignore。注意retry时,会致使表达式又一次求值.
MemWatch有个默认的ARI处理器。默认是关闭的,但你能经过调用mwDefaultAri()开启。注意这仍然会停止你的程序除非你定义MEMWATCH_STDIO赞成MemWatch使用标准C的I/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,那么可以在这个函数上设置运行断点。
其它功能的使用,请參考源码的说明。
日志文件memwatch.log中包括的信息主要有下面几点:
Ø 測试日期
Ø 状态搜集器的信息
Ø 使用MemWatch的输出函数或宏(如TRACE等)的信息。
Ø MemWatch捕获的错误信息
Ø 内存使用的全局信息统计,包含四点:1)分配了多少次内存 2)最大内存使用量3)分配的内存总量 4)为释放的内存总数
MemWatch捕获的错误记录在日志文件里的输出格式例如如下:
message: <sequence-number> filename(linenumber), information
mwInit()和mwTerm()是相应的.因此使用了多少次mwInit(),就需要调用多少次
mwTerm()用于终止MemWatch.
假设在流程中捕获了程序的异常中断,那么需要调用mwAbort()而不是
mwTerm()。即便有显示的调用mwTerm(),mwAbort()也将终止MemWatch。
MemWatch不能确保是线程安全的。假设你碰巧使用Wind32或者你使用了线程,做为2.66,是初步支持线程的。定义WIN32或者MW_PTHREADS以明白支持线程。这会致使一个全局相互排斥变量产生,同一时候当訪问全局内存链时,MemWatch会锁定相互排斥变量,但这远不能证实是线程安全的。
从MemWatch的使用可以得知,没法用于内核模块。因为MemWatch自身就使用了应用层的接口,而不是内核接口。但是,对于普通的应用层程序,我以为仍是比較实用,并且是开源的,可以本身改动代码实现;它能方便地查找内存泄漏,特别是提供的接口函数简单易懂,学习掌握很是easy,相应用层程序的单元測试会较适用。
博主的新Blog地址:http://www.brantchen.com
欢迎訪问:)