SCMLife.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 6672|回复: 2

[推荐] 深入浅出 IBM Rational PurifyPlus 高级特性

[复制链接]
发表于 2011-11-21 17:46:08 | 显示全部楼层 |阅读模式
本帖最后由 技术狂人 于 2011-11-21 17:50 编辑 7 _& U) X  G" u% j& o7 u  F  u

5 B% \0 Z# W8 `3 c; n. _/ [$ V简介
6 I' A% _1 i5 F$ @* wIBM Rational PurifyPlus(以下简称 PurifyPlus)一个强大的动态代码分析工具。它由三个工具组成:IBM Rational Purify、IBM Rational Quantify 和 IBM Rational PureCoverage(以下简称 Purify、Quantify 和 PureCoverage)。Purify 专注于内存检测,其高级内存调试功能能够查找内存错误的根源并提供错误位置等详细信息。PureCoverage 用于测试代码覆盖率,能够提供精确到行级别的覆盖率信息。而 Quantify 用来测试代码性能,它能够提供图形化的函数调用展示,突出性能瓶颈,以供性能调优之用。. k) l: i8 N3 C
PurifyPlus 支持的系统包括 Windows 及 UNIX,支持的编程语言包括 C、C++、Microsoft .NET 和 Java 等,PurifyPlus 在您的程序运行时通过注入的代码监测您的程序,并报告所有发现的问题。
! j* Z9 \& c! Y5 e除了创建错误报告,PurifyPlus 还包含一些高级选项,能够帮助您对 PurifyPlus 进行定制,以满足复杂软件开发环境的需求。
" H# F! J  ^# K$ H5 I+ i. W4 o9 t/ n本文中,我们将按以下几个方面进行阐述:( H& G* @; E8 s$ V& X0 U; L' T, T
  • PurifyPlus 基本使用介绍
  • 选项的使用方法
  • 缓存管理:介绍如何管理和共享被注入过的二进制文件
  • 控制输出
  • 消息过滤:介绍如何控制错误报告中显示的各种消息
  • 选择性注入:介绍如何对应用程序中的某一部分进行注入,以缩短注入时间并缩小错误检测的范围
  • 堆内存管理:介绍如何限制注入时占用的时间和内存
  • 覆盖率分析/ m& w4 s9 A; t+ K" m  g4 [) T4 {& [


3 Q; X. I7 \" L6 w5 U( R  `
8 H) D. A) t7 H; ^PurifyPlus 基本使用介绍3 L7 o. Y3 ?( y! [: i
首先以 hello, PurifyPlus 程序(程序见程序清单 1 程序 A)为例来介绍如何在 UNIX 平台上使用 Purify。这是一个 .c 程序,要使用 Purify 对他进行分析,只需在编译的时候在 gcc 前面加上“purify”:3 G. i6 D* g& x& U" n7 h
$purify gcc test.c -o test.p

. V" x1 J% p$ O9 m; W8 u然后执行 purify 过的程序即可 :; K+ J6 [- P, c5 n2 E2 n" t
$test.p

! f8 n4 V3 x* Q8 h* N) A3 M弹出结果如下:
' V# @9 j& o' K1 o* u4 `+ A1 E" P
图 1. Purify 在 UNIX 平台下执行结果界面( J1 G3 ^# e# o. I. b( R
7 D' `: z6 l( k9 g+ S' @8 s) B4 k
接下来,我们再来看看 Purify 在 Windows 平台上的使用。您可以在命令行使用类似 UNIX 平台的命令,也可以使用图形界面,直接在界面上选择您要 Purify 的可执行程序,然后选择执行即可。以下以 hello.exe 程序(在 PurifyPlus 安装路径下的 Samples\Purify 目录里可以找到这个程序)为例。
6 l' d' @0 \% m4 q$ I" K" L首先在 Windows 开始菜单中选择 Purify 程序,在弹出的 Purify 欢迎界面中,选择“Run”,如图 2 所示:( b7 w" a, ~9 G1 v

: R8 ?4 S  \' o+ }9 g图 2. Purify Windows 平台下的欢迎界面' C0 T3 r; W4 q: F
+ M; }# c/ e- y3 P
然后选择要 Purify 的程序,这里是“hello.exe”,点击“Run”,如图 3 所示:
" _& Q9 z9 i' s8 O5 `! V; v4 e
% h: m$ _1 E" m8 N# ]5 X$ I2 e& V图 3. 选择要 Purify 的程序* y* G3 _) \/ ^/ t1 k( X

7 W+ N/ G0 t$ o* ?/ N# E" m% f, U6 a接下来,Purify 便开始对应用程序进行注入,并将分析结果显示在界面上,执行程序的执行结果也将显示,如图 4 所示:
) k! Q9 k/ J+ i# i5 u$ c! D: t
+ f/ P4 J3 o9 ~# m2 ^图 4. Purify 执行结果界面
, t: Q  k, ~$ h $ l; f- }" D, K7 }! ]/ X
$ i0 \- U+ s1 h" N8 L, E" J
在 hello 程序执行结果界面上点击“确定”,让程序完成执行,Purify 随即将整个分析结果显示出来,如图 5 所示:+ t( X9 l$ l& g  I

$ u; ?1 m/ Q2 U7 z) u# N$ r图 5. Purify 最终执行结果界面+ t: I% v! y; j3 x. g9 q

# N& C( C- p; m  T+ ^- K4 q# Z! L, [; v9 N) c
Coverage 和 Quantify 的使用与 Purify 类似,这里就不再一一举例。如您需要可从以下的资源链接里得到更多的信息。1 Q( B1 F3 R7 q( h% C3 ?
现在您对 PurifyPlus 的使用已经有了一个基本的了解,下面我们将就 PurifyPlus 的高级特性进行介绍。, p1 ^) S/ k2 o5 J6 o8 j


# B+ r; R: J9 N4 |2 m9 o
. w- J  O3 ?7 T$ e3 Y- H选项的使用方法
3 Q; ^8 s/ G: v2 Q* X! bPurifyPlus 的选项主要可以分为以下两类:" G5 z3 M6 J5 D# E" S! \% R9 M
  • 编译时选项:编译时选项在代码注入阶段使用。编译时选项有很多,比如您想指定自定义的缓存路径,您可以使用 -cache-dir=<cache-home> 选项,这样程序在被注入的过程中能够使用自定义的缓存路径。
  • 运行时选项:运行时选项在运行已经被注入过的程序时使用。PurifyPlus 支持很多运行时选项 , 您可以查询 PurifyPlus 的帮助手册或 -options 命令得到所有的运行时选项,例如,您可以使用 -windows=yes/no 来控制是否用图形化来展示执行结果。
    8 B) q8 w4 H: t$ G) G
使用选项有两种方式,一种是设置在环境变量中,另一种则是直接在命令行中设置。- @6 M0 I3 }8 j- g. _' q) B8 J# a' D+ c
  • 环境变量
    1 ?+ \) G, F) u: e( o6 z" f2 }
设置 PUREOPTIONS8 N! F; R* y3 ?1 R6 H
  • PUREOPTONS 环境变量作用于 PurifyPlus 的全部产品 Purify、PureCoverage 和 Quantify。例如,在 csh shell 中使用:8 ^* `9 k' i! C  l0 X5 q3 ]! Q
$setenv PUREOPTIONS "-static-checking=no -chain-length=10"
1 N6 l1 ~1 v& e9 c. x
设置 PURIFYOPTIONS/PURECOVOPTONS/QUANTIFYOPTIONS 环境变量。
, [, h3 f+ r3 Q) R/ n" f
  • PURIFYOPTIONS 环境变量作用于 Purify 产品
  • PURECOVOPTIONS 环境变量作用于 PureCoverage 产品
  • QUANTIFYOPTIONS 环境变量作用于 Quantify 产品* S1 U" l6 ]! ~
在 csh 中我们可以通过设置 PURIFYOPTIONS 环境变量来自定义 Purify 的选项。例如:  b  n8 |/ o3 U! d  ^
$setenv PURIFYOPTIONS "-static-checking=no -chain-length=10"

' c" i' L8 z& y, ?* k! M9 O5 e
  • 命令行选项
    - Z& \3 t+ }6 h: k
$purify -static-checking=no –chain-length=10 $cc –g test.c –o test.p

0 g9 `9 I% K0 S7 k  B小贴士如何保证应用程序的运行时选项不受到其它用户的影响?4 l5 g: D- _: x! |- o. `
我们可以通过 -ignore-run-time-environment 选项来屏蔽其它环境变量的影响。
+ g' L* w+ t$ w# r, }+ p8 I' D8 M

" c7 \1 |) ~+ R/ u; R/ n

+ ^3 c0 b. D1 x
/ A* P. @4 s& I' \6 ?: t7 ~缓存管理(Cache Management)# l0 l$ F0 ^( w5 P% y
基本介绍
. A" L3 N4 z/ s/ x+ g* N在 PurifyPlus 注入目标程序的同时,还会注入那些被程序直接或间接引用的类库,并用这个被注入过的版本来替换原程序所引用的版本。; X3 C4 i4 |) w. }+ p
如果用来存放这些类库的目录是可写的,那么 PurifyPlus 会直接在该类库所在目录下生成这个被注入过的版本;如果用来存放这些类库的目录不可写,那么 PurifyPlus 会在自己的默认缓存目录下生成这些被注入过的版本。9 H' _; C- T5 d, g% ]2 b
相关选项
/ t. p2 H0 ~4 bPurifyPlus 提供了丰富的与缓存有关的选项。例如:
/ r) L' s- z1 R6 R: |# o3 v-always-use-cache-dir 选项
( p; \. o- m1 u. _- e如果您不希望那些被注入过的类库被随意存放,您可以使用 -always-use-cache-dir 选项,这样所有被注入过的版本全部都会被放置在缓存目录中。$ ]- L3 O8 K+ T+ R3 b/ _6 i
-cache-dir 选项
5 ?; d1 r+ o3 q# F; o* a. y+ w您可以使用 -cache-dir=<dir-name> 来指定一个特殊的缓存目录,这样可以通过直接删除这个缓存目录来清除所有被注入过的类库。9 X* ^2 K% J# g: _) b
-force-rebuild 选项
% t( t3 P$ w/ F/ Z7 m) y) Q/ ^当 PurifyPlus 注入一个应用的时候,PurifyPlus 只会注入那些没有被注入过,或者自从上次注入之后又发生了变化的类库,这样有助于缩短注入时所耗费的时间。但如果您不想重复使用那些先前已经注入过的类库,您可以使用 -force-rebuild 选项,这时 PurifyPlus 会重新注入所有类库。
3 Z1 R3 r+ [7 t1 N如何清理缓存6 f6 ?2 i8 @" W$ I% z- M' M+ P
您可以通过运行 PurifyPlus 安装目录下的 pure_remove_old_files 脚本来清理被注入过的类库:4 }4 |3 o, ^! E
$`purify -print-home-dir`/pure_remove_old_files <path> <days>

: {' B6 ]- g8 f$ P通常情况下,这些被注入过的类库名称中都会包含 _pure_ 字段并以共享库扩展名(例如 .so 或者 .sl)结尾。您可以通过如下方式清除文件系统中所有超过 14 天的被注入过的类库:
/ E# H$ g5 q6 ]% k% M; E- u$ E
$ pure_remove_old_files / 14

+ Z* ?( `7 x0 @1 R' i) i$ m1 f

% I4 x; c2 p# {4 N( M, q- ^6 Y: n. M+ J& u7 I, L
控制输出
( c& t3 F8 p" ^& T$ O# v通过控制输出可以使您的分析结果保存成不同需求的格式,更易于维护和管理。
, x6 q- ?( }9 Y+ ?6 z4 E文本输出3 x9 J8 ?4 P' y6 \
在默认情况下,PurifyPlus 的结果信息是在图形界面上展示的。假如您不想使用图形界面,只想生成文本结果,可以通过设置运行时选项来实现。例如:& Z. m. S: c7 M# ?; x
$purify –windows=no -log-file=<filename>.plog $cc –g test.c –o test.p $quantify –windows=no -log-file=<filename>.plog $cc –g test.c –o test.p

4 F7 v) k; G+ C: t& K2 \另外,Purify、PureCoverage 和 Quantify 均支持运行时选项 -log-file 来保存日志文件,例如:0 J/ H2 C6 u: p
-log-file=<filename>.plog

' N' w8 q" I% [" U/ j6 D二进制输出! n' Q! J; a5 ~+ e3 Z
二进制输出可以通过 PurifyPlus 的图形界面来展示。您还可以通过以下命令来生成二进制结果文件:
$ e, G  `- T: D$ G% C7 L( O
$purify –view-file=<filename>.pv $purecov –counts-file=<filename>.pcv
0 X5 k; o- n& p- l8 d6 O3 I: U& L( R6 C8 i8 q
-view-file 选项会生成 Purify 图形界面能展现的报告文件,-counts-file 选项是生成 PureCoverage 图形界面能打开的结果文件。5 f' W9 G1 e; i' ~
对 Quantify 来说,只要设置 -windows=no 参数,就会自动生成扩展名为 .qv 的结果文件。# M! o3 [$ h* i, V" r: D$ d' \; J) d
在成功生成结果文件之后,我们可以使用运行时选项 -view 来查看这些文件:# j. v4 }. c6 R  i
$purify –view <filename>.pv $purecov –view <filename>.pcv $quantify –view <filename>.qv
% X) `, L3 C. ?. l- v8 d6 ]" \


) g4 L2 D3 _  i" c$ X0 D$ `0 p- \0 D% f" e- s
消息过滤(Suppression)
9 p% ^9 F, y' \3 r在使用 Purify 的时候,我们可以通过图形界面或过滤文件来过滤消息。
7 x  K# f: m2 Y1. 使用图形界面$ s6 r7 b- @* B# K; l
我们以下面的程序 A 为例,来看看如何使用图形界面进行消息过滤。4 x% p. T$ d% K2 E
5 I$ w) H! a% f% R, h3 I9 v
程序清单 1. 程序 A+ E* j8 O5 r) ^- ]. T5 v& ?
#include<stdio.h>#include<stdlib.h>void demo_printf(char *message) { printf(message);}void demo_abr(char *str) { char *abr_err=(char*)malloc(strlen(str)); strncpy(abr_err,str,18); demo_printf(abr_err);}int main() { char *str="Hello,PurifyPlus!\n"; demo_abr(str); return 0;}
9 x. i4 u& H2 l% W
在 Purify 的 Viewer 视图中,选择 Options,点击 Suppressions。然后在弹出的对话框中,可以选择需要过滤的消息类型,以及在什么调用关系中过滤。例如,在图 6 中选择过滤 Array Bounds Read(ABR) 即数组越界读,其调用关系是 main -> demo_abr -> demo_printf -> printf-> _ndoprnt。最后点击 Apply,则满足该调用关系的 ABR 消息将会被过滤掉。' W0 |; B- z7 }$ q6 C& o
0 a3 z/ d1 ]4 O* _( ~1 k
图 6. Suppressions 界面9 j' ^2 m  t6 w3 x# t

7 a% u9 v6 ~0 \* {9 X2. 过滤文件
6 F3 S. R; c! l& s* e) [2 g: G& C使用过滤文件,主要是把用于过滤的执行语句写在 .purify 文件中,该文件将保存在应用程序所在目录中,Purify 启动后会自动载入这个文件,这样就可以达到控制过滤消息的目的了。以下是过滤文件的语法:2 Q% c* L0 p" Q' K( x: W
suppress <message-type> <function-call-chain>

/ x1 b# I/ s& E7 ?其中,suppress 为关键字,表示过滤;<message-type> 指明要操作的消息,可以使用 * 号作为通配符;<function-call-chain> 表示用分号分隔的函数调用链,同样可以使用 * 号作通配符,还可以使用”…”省略号来表示中间任意层的调用。以下是一个具体的例子:
# I  \5 H5 K: P0 \2 ^% Q! |/ X% Y% A
' @5 S  ?( V! J% T1 I文件清单 1. 过滤文件 A
% f  o" r8 @) p" M! J1 c% }; W
suppress AB* *suppress MLK“libc.so.1”suppress ABR _ndoprnt; printf; demo_printf; demo_abr; main;suppress ABR ndoprnt;…; main;

) a  ?) D3 \; w, r( Y. e" R每行的过滤功能分别是:$ D& A# b6 R# O1 X" ~
  • 第一行表示忽略所有以 AB 开头的错误,例如 ABR 和 ABW(Array Bounds Write 即数组越界写)错误。
  • 第二行表示忽略 libc.so.1 文件中的所有 MLK(Memory Leaks 即内存泄露)错误。
  • 第三行表示忽略函数调用关系满足 main -> demo_abr -> demo_printf -> printf -> _ndoprnt 时出现的所有 ABR 错误。其中 printf 和 _ndoprnt 是标准库函数 (libc.so.1) 中的函数。
  • 第四行表示忽略 ndoprnt 函数中的 ABR 错误,只要该 ndoprnt 函数是被 main 函数间接调用的,无论函数调用层数有多深。如果你设置了参数“-chain-length=10”,那么最多只能深入到第十层函数调用。6 Z/ {1 f7 q. t" y2 {' H
在启动 Purify 时,我们可以这样来读取 .purify 文件:0 t  m  x6 j, A, `5 x: V% L
$purify -suppression-file names=".purify"

9 K! ]0 n6 T* w7 b8 R  u" e. @
" @. _6 q* [# ?" `6 I9 h

" P  f- j4 X- Y& t1 d0 ~- {选择性注入(Partial Purify)
$ a+ f: f6 m, s8 f4 h& D' a: t! ZPurifyPlus 的工作原理是向二进制代码的特定位置注入少量必要的代码和注释来追踪非正常的内存访问。有时候您会希望 PurifyPlus 能够只检查某些特定的模块或组件,比如您对第三方类库中的错误不感兴趣,而只关心您程序本身的问题。在这种情况下,就需要有选择的对您的应用进行注入并过滤掉那些不感兴趣的第三方类库。7 @$ J2 l, X* ~3 ]- v- O) a
这一机制保证您可以仅仅注入那些重要的组件,这样即便应用非常之大,您也可以非常轻松的控制注入过程所需要耗费的时间。
* x3 X+ K  r) X( D: J4 n. a: |当您有选择性的过滤掉某个类库时,PurifyPlus 仍然会监测这些类库中的堆栈异常,例如内存泄漏。
. H. t% T6 b3 [8 ]$ n8 \9 O2 G4 v您可以通过下面这种方式来实现选择性的注入某个类库:) f$ C# [& p# u& [% [! C
$purify -selective -exclude-libs=libfoo1.so:libfoo2.so \ cc -g app.c -o a.out.pure -lfoo1  -lfoo2 -lbar

2 Z! k' f; m1 n/ U& Z% \( W您可以通过在命令行参数中加入 -exclude-libs 来指定一个冒号分隔的类库列表,也可以在 .purify 文件中加入一行:# |" g0 U6 \' W1 x7 e
exclude libfoo*

  I1 o; |; C* C" P# h2 _其中的 * 号代表任意的数字和字符。3 I/ x$ l+ I& j* `, Z
-selective 选项使得 PurifyPlus 调用一个更完善的算法来检测和排除那些由被过滤的类库带来的假错误。例如:0 F& N4 b7 v2 j  m) P) \% D6 C  f
  • 某个应用中的 main() 方法调用了 foo() 方法(假设该方法存在于 libfoo.so 中),foo() 又调用了 bar() 方法,而您又选择过滤了 libfoo.so。再假设在 main() 方法中分配了某块内存空间,而 foo() 初始化了这块内存空间,最后 bar() 使用了这块内存空间。因为 foo() 没有被注入,所以 PurifyPlus 将不会知道这块内存空间已经被 foo() 初始化过,这样在 bar() 方法使用这块内存空间的时候,PurifyPlus 可能会报出一个未初始化内存读取(Uninitialized Memory Read – UMR)的错误,而 -selective 选项可以让 PurifyPlus 避免发生这样的误报。' G0 q' x5 _' h  M9 t& r4 B. s
  • 另外一种情况是,过滤掉某个类库可能会让 PurifyPlus 漏报某些错误。例如我们假设 main() 方法调用 foo() 方法时传入了一个未经初始化的缓存变量,通常情况下,PurifyPlus 会在 foo() 每一次读取该变量时报告一个 UMR 异常。但如果 foo() 是在被过滤掉的类库 libfoo.so 中,这种情况下 foo() 并没有被注入过,所以从理论上来说 PurifyPlus 不会对其进行内存检查。但实际情况是 PurifyPlus 同样会报出异常,因为 main() 向 foo() 中错误的传入了一个未经初始化的缓存变量。
    ( ?& n& ?) V8 L4 i
这两个例子很好的说明了缩短注入时间和有效发现异常之间的关系,这就意味着您需要谨慎判断这些类库是如何与您的应用进行内存相关交互的,以及他们是否可以被过滤。! p7 m8 k. H, ]' d3 @- C
另外 PurifyPlus 还可以检测那些未注入代码中的缓存使用异常,这些问题可以在缓存释放时被发现。这时候您需要使用 -late-detect-logic 选项,这样 PurifyPlus 会在堆栈内存被释放的时候进行额外的检查,如果检测出了缓存调用的异常,PurifyPlus 会报告一个 Array Bound Write Late (ABWL 即延迟检测数组越界写 ) 的异常。9 L- j2 ?- b# `- ~, W' p

8 d7 Z' v5 r  V: \: o0 W
2 ]; u  F9 W, I% f" s( b
堆内存管理 (Heap Management)8 ^; f# H0 ]* R* y1 M
在注入一个目标程序时,PurifyPlus 提供了一些选项来控制注入时对内存和时间的过度占用。# ]) [6 Y- k3 e! P4 v8 X7 l* j$ A
当您的程序释放了一块内存空间时,PurifyPlus 不会立即释放这块内存,它会把这块内存先放到一个先进先出队列里。这样 PurifyPlus 就可以在您的程序试图访问这块已经被释放的内存时,发现并报告已释放内存读或写错误(Free Memory Read/Write)。
7 n# f+ [7 k' H- _: L' T* M这个先进先出队列的默认长度是 100。当队列满的时候,PurifyPlus 释放队列里的第一个内存块,并将一个新的内存块加在队尾。您可以通过 -free-queue-length=<value> 选项来修改队列的长度。扩大队列长度可以增加 PurifyPlus 的检测范围,但同时也会占用更多的物理内存和虚拟内存。
4 C3 y5 W. r# Z% P& |, a另外这一队列通常只在小内存块中使用,超过一定阀值的大内存块会被直接释放回堆栈,这样可以避免占用过多内存的风险。您可以使用 -free-queue-threshold=<value> 选项来设定这一阀值的大小,默认值是 10,000 字节,任何超过这个大小的内存块都会被立即释放。9 D" Y" v3 v8 ?% W2 c; N3 v0 y
PurifyPlus 会在程序运行结束后报告所有的内存泄露问题。如果您还希望检查所有仍使用着的内存块,您可以用 -inuse-at-exit=yes 选项。您还可以用 -fds-inuse-at-exit=yes 选项来检查程序退出后仍在使用的文件描述符。
* f8 W4 ~# I0 i, q在 AIX 系统中,假如您只希望查看所有的内存泄漏问题,您可以使用 -memory-leaks-only 选项,此时 PurifyPlus 会做非常轻量级的注入,仅仅检查内存泄露和其他堆栈管理错误,例如 Freeing Memory Mismatch (FMM) 错误。这样您的程序会运行的更快一些,因为 PurifyPlus 会省掉很多通常对内存访问所做的检查。
& ]+ T7 J0 R1 l" {! I6 ?! T& _1 k! X& t如果您在运行的时候设置了 -leaks-at-exit=yes 选项,PurifyPlus 会在程序运行结束的时候显示所有内存泄漏的情况。如果您还想获得堆内存使用的情况,请使用 -inuse-at-exit=yes 选项。
' E0 z" l. v! @5 P, r7 h" [例如:
- i9 o5 S6 d8 ]# E' Z
$setenv PURIFYOPTIONS "-free-queue-length=100 -free-queue-threshold=10000 \ -inuse-at-exit=yes -fds-inuse-at-exit=yes -leaks-at-exit=yes"

, n+ h9 `7 r- G% Y( x/ W$ V这一选项使得 PurifyPlus 在程序运行结束的时候报告所有依然被占用的内存、文件描述符以及内存泄露的情况。
1 m1 q* }) p" K8 w: M8 S1 o
  g6 u; s6 I& e" M# N3 J' W! Q- j

8 J& d) z) l! O  s! _覆盖率分析
1 W, @. z; c3 U% [PureCoverage 还有一个归并(merge)功能,允许您归并和比较同一程序多次运行(不同操作)所生成的覆盖数据,从而可以快速评估覆盖率是否符合标准。3 F8 L$ h0 O3 t4 ~9 i; o4 Z
以下是使用方法:
5 r$ g" P( h/ x  Q2 o- c
$purecov –merge=result.pcv a.pcv b.pcv
5 m5 L0 w1 {; b& w- ^% H" B# S


- q' o  Q, u6 S0 @' p( K. `' o( Q
小结
% P  p: B' W: l' S  B本文介绍了 PurifyPlus 的高级选项和命令,及如何用它们来管理 PurifyPlus 的缓存,减少时间消耗和检查堆内存使用情况,这将有助于您自定义 PurifyPlus 以满足您的不同需求。7 P  P4 J, O6 K

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
 楼主| 发表于 2011-11-21 17:47:54 | 显示全部楼层
回复 支持 反对

使用道具 举报

发表于 2013-10-17 14:13:01 | 显示全部楼层
好强大,收藏了,希望有用
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|无图版|SCMLife.com ( 京ICP备06056490号-1 )

GMT+8, 2018-1-18 00:08 , Processed in 0.076700 second(s), 6 queries , Gzip On, MemCache On.

Powered by SCMLife X3.4 Licensed

© 2001-2017 JoyShare.

快速回复 返回顶部 返回列表