十、 设置WatchPoint
你可以在你的程序中,对你所想监控的程序设置一些
WatchPoint
,以方便于你对程序进行调试,或更容易找出问题的原因。就像我前面说,
Purify
可以找到你的内存泄露,但其不能找到内存泄露的原因,你可以通过设置
WatchPoint
来跟踪一块内存,以找到在程序执行过程中该内存的访问情况。
Purify
的
WatchPoint
可以产生下例消息:
l
WPR
(被
WatchPoint
的内存读)
l
WPW
(被
WatchPoint
的内存写)
l
WPM
(被
WatchPoint
的内存分配)
l
WPF
(被
WatchPoint
的内存释放)
l
WPN
(来到被
WatchPoint
的内存的
Scope
)
l
WPX
(离开被
WatchPoint
的内存的
Scope
)
一旦你设置好了一个
WatchPoint
,
Purify
会自动报告上述这些信息,以告诉你内存的存取情况。很方便你调试程序。
WatchPoint
一般是在调试程序时跟踪一块内存时候使用的,你也可以用其跟踪一些系统级的全局变量,如:
errno
。一旦
errno
被写了,马上会报告一个
WPW
消息,展开后,你能看到函数的堆栈情况,以及是在哪个系统调用后出现了错误。这个使用很方便我们找到一些非内存方面的问题。
大家可能会有一种感觉,那就是在一般的调试器中,如
GDB
中也有
WatchPoint
的设置(对
GDB
的使用请参考我的文章《
用GDB调试程序
》),那么,在调试器中的
WatchPoint
和
Purify
的有什么不同?下面是一些
GDB
中的
WatchPoint
不足的地方:
1)
GDB
中的
WatchPoint
用于单步跟踪中。
2)
GDB
中的
WatchPoint
只能在其内存的
Scope
中,离开了
Scope
,
WatchPoint
会被删除。
3)
在
GDB
中设置一个
4
字节的内存
WatchPoint
,会让程序的运行效率下降
1000
个数量级。
Purify
中的
WatchPoint
有效地克服了这些问题,它在全局范围内监控所有内存的使用,并且,其速度上大大地快于
GDB
等一系列的调试器。
有两种方式可以让我们设置
Purify
的
WatchPoint
,一种是在程序中使用
WatchPoint
的
API
函数,一种是直接在调试器中使用(如:
GDB
),下面我介绍一下这两种用法:
1、
在程序中使用。
写下这段程序:
#include <errno.h>
main()
{
int i;
printf("Note: errno=0x%x\n", errno);
purify_watch(&errno);
errno = 0;
close(1000);
exit(0);
}
|
用
Purify
编译:
>sudo purify gcc -g -o watch watch.c
运行后,我们可以看到以下画面:
我们可以看到,
Purify
成功地监控了
errno
变量。我们还可以看到被监控的变量改变前和改变后的值。
2、
在GDB
中使用。
在
GDB
中,我们可以简单地使用
GDB
的
print
命令来达到设置
Purify
的
WatchPoint
目的。这正是
Purify
的强大之处,其对这种技术称为
JIT
(
Just-In-Time
)。
示例:
gdb) print purify_watch(&my_str)
(gdb) print purify_watch_1(&my_char)
(gdb) print purify_watch_n(buf, sizeof(buf), "rw")
(dbx) print purify_watch_n(write_only_buf,100,"w")
下面来让我们看一看
Purify
的
WatchPoint
的
API
函数,其分成三类:
•
设置类
int purify_watch(char *addr)
对所指定的内存进行监视,
char*
表示以单字节为单位。
int purify_watch_<num> (char *addr) <num>=1,2,4,8
其中的
<num>
是一个数字,可以是
1
,
2
,
4
,
8
表示,监控单字节,双字节,四字节,八字节。函数名为:
purify_watch_1()
,
purify_watch_2()
,
purify_watch_4()
,
purify_watch_8
。
int purify_watch_n(char *addr, unsigned int size, char *type)
(type = “r”, “w” or “rw”)
监控特定长度的内存,
type
取值为“
r
”,“
w
”“
rw
”,意为监控内存的读还是写。
•
查询类
int purify_watch_info().
打印目前设置的
WatchPoint
的情况(一般在
GDB
类的调试器中使用)。有点像
GDB
的
info watch
命令。
•
删除类
Int purify_watch_remove(int watchno)
删除指定的
WatchPoint
,其
watchno
为设置
WatchPoint
的函数的返回值。
int purify_watch_remove_all()
删除所有的
WatchPoint
。
十一、 使用Purify的参数
Purify
的参数很多,具体的参数我就不多说了,还请你参考其使用手册。在这里,我简单地讲一讲其参数的使用规则和方式。
Purify
的参数使用的规则如下:
1、
必须以连字符开始,也就是减号。
2、
在等号(
=
)的两端不能有空格。
3、
忽略参数名和变量的大小写。
4、
其参数中的连接符可以是减号,下划线,或是干脆就没有。如:
-leaks-at-exit
,
-LEAKS_AT_EXIT
和
�CLeaksAtExit
是一回事。
5、
在参数中,如果你要指多个路径,可以用冒号或空格分开。使用空格时请使用引号。如:
% purify -user-path=’/usr/home/program /usr/home/program1’
% purify -user-path=/usr/home/program:/usr/home/program1
6、
指写多个邮件用户时,用逗号分隔。千万不要回空格。如:
% purify -mail-to-user=chris,pat,kam
7、
可以使用通配符或转义字串。如:
program*
和
-log-file=./%v.plog
Purify
参数的类型有三种――布尔、字符串和整数,如:
-leaks-at-exit=yes
布尔型
-log-file=./pureout
字符串型
-chain-length=10
整数型
设置参数的方法有三种:
1、
在图形窗口中,通过点击“
Options -> Runtime
”菜单,在对话框中设置。
2、
通过两个环境变量设置――
PURIFYOPTIONS
或
PUREOPTIONS
,如:
在
csh
下:
% setenv PURIFYOPTIONS "-log-file=new $PURIFYOPTIONS“
在
sh
或
ksh
下:
$ PURIFYOPTIONS="-log-file=new $PURIFYOPTIONS"; export\
PURIFYOPTIONS
3、
在
Link
程序的命令行中。如:
$ purify -cache-dir=$HOME/pcache -always-use-cache-dir $CC ...
十二、 使用Purify的API函数
Purify
的函数有许多,我也不在这里一一讲解了,其具体细节还请参考使用手册。我这里只讲一下
Purify
的
API
函数的使用方法。总的说来,有以下两种方式我们可以使用
Purify
的
API
函数。
1.
在我们的调试器中调用,如:
gdb) print purify_describe(addr)
(dbx) call purify_what_colors(buf, sizeof(buf))
(xdb) p purify_describe(addr)
注:对于
purify_stop_here
这个函数,我们可以这样使用。
(gdb) break purify_stop_here
(dbx) stop in purify_stop_here
(xdb) b purify_stop_here
2.
在自己的程序中调用。要在程序中调用
Purify
的
API
函数,我们需要下面两步:
1
)加上头文件:
#include <purify.h>
2
)把
LIB
文件放到可被搜索到的路径中。主要是一个动态链接库文件
libpurify_stubs.so
和一个静态链接库文件
libpurify_stubs.a
十三、 结束语
Purify
是一个很强大的工具,但可惜的是其只能是某几个平台中使用。好像其
Windows
版中的功能要差很多,我用的
Sun
的
Solaris
的版本,很不错,因为我们的程序要在所有的
UNIX
下跑,用
C
跨平台,所以,使用
Solaris
来做测试机。对于其它平台的
Purify
,我没有用过,不知道和
Solaris
下的是否一样,还希望有经验的同行给我指点。不管怎么样,我想信IBM的Rational部会把它做得越来越好的。
对于这篇文章,本来打算在
9
月或者
10
月写这篇文章的。不过实在没有办法,前些时候太忙了,忙得脑子一堆浆糊,只要拖到现在,现在较好一点,不过脑子也不好用,写作过程中发现脑袋很拙笨。所以写出来的东西一点有错误,特别是我用的是五笔输入法,所以有错字错词会有可能让你看不懂,还请各位见谅。
好了,不多说了,好累了。还是留上我的联系方式,欢迎和我讨论交流。本人目前主要在
UNIX
下做产品软件设计和管理工作,所以,对
UNIX
下的软件开发比较熟悉,当然,不单单是技术,对软件工程实施,软件设计,系统分析,项目管理我也略有心得。欢迎大家找我交流。(
MSN
是:
[email protected]
(常用)
QQ
是:
753640
(基本不用,因为不安全))
(全文完)