1、 IBM Rational运行时分析解决方案 1 引言 本文介绍了什么是软件代码运行时分析,为什么要进行软件代码运行时分析,以及IBM Rational如何通过工具Rational PurifyPlus帮助开发人员在软件开发过程中成功运用运行时分析,从而尽早发现代码中的功能逻辑、内存以及性能问题,提高软件系统的质量。 2 软件运行时分析 2.1 什么是软件运行时分析? 运行时分析是指通过分析在软件执行时所收集的数据来理解软件的内部运行状况,通常被开发人员用来检测和定位应用问题的一种测试技术,这些问题包括内存访问错误、内存泄漏、性能瓶颈、资源使用不合理以及未被测试的代
2、码。 运行时分析技术具有两个特点: 1、 运行时(Runtime):该技术不对软件代码进行静态分析,而是通过运行软件系统或组件,来获得软件的内部执行信息。 2、 分析(Analysis):指开发人员对暴露的或潜在的问题进行合理的解释。 运行时分析提供如下方面应用执行时信息: 1、 执行路径 2、 代码覆盖 3、 运行时跟踪 4、 内存使用情况 5、 C/C++应用的内存访问错误和内存泄漏 6、 .NET应用和Java应用的内存泄漏 7、 性能分析 8、 线程分析 要收集软件内部的执行状况信息,首先要对代码进行插针。在日常开发活动,我们其实经常应用该技术。如下面的代码:
3、 If( a > b){ ... printf(“DEBUG: IF BRANCH\b”); }else{ ... printf(“DEBUG: IF BRANCH\b”); } 代码中的printf语句实际就是我们为了知道程序运行哪个分支而加入的指令,我们把该种方式成为手工插针。这样在代码编译、连接、运行后,通过程序的输出信息就知道哪个分支被执行。 2.1.1 为什么要进行运行时分析? 众所周知,开发人员经常使用调试(Debugging)技术来定位问题。开发人员保证代码能编译、连接通过,并验证软件的基本功能满足。而测试人员通常也是更多关注与系统的主要功能和使用模式。但
4、在生产环境中,由于使用模式的组合,或运行一些没被测过的使用模式,将导致系统崩溃或有性能问题。开发人员和测试人员都有责任避免软件缺陷,而最好的方式就是在开发的早期进行充分的测试,尽早发现问题。 但是开发人员在测试自己的软件模块时,通常采取一种正向思维,也就验证软件的基本功能。据统计,这种方式通常只能测试30%到40%的代码块。而通过运行时分析提供的代码执行覆盖情况,开发人员可以逐步丰富测试用例,从而保证大部分的代码逻辑被测试,最终提高测试完备性,提高软件质量。 同时,通过运行时分析,还可以尽早发现代码中的内存问题和性能问题,提高代码质量。 3 利用Rational工具进行代码运行时候分
5、析 当今软件开发项目主要采用C/C++和Java作为开发语言,但这两种语言在本质上有如下不同: 1、 执行机制不同:C/C++代码经过编译、连接形成的目标代码是直接运行在操作系统上。而Java代码经过编译后,是运行在Java虚拟机(Java Virtual Machine,JVM)上。 2、 内存管理机制不同:C/C++提供动态显式的内存分配机制(如malloc和free),由程序代码管理内存的分配和释放,而Java的内存分配机制主要通过JVM提供的内存对象垃圾回收机制来实现。 3.1 利用PurifyPlus对C/C++代码进行运行时分析 PurifyPlus包括三个功能模块P
6、urify,Quantify和PureCoverage。功能分别如下: 1、 Purify:用于检测C/C++代码中的内存错误和内存泄漏 2、 Quantify:用于发现C/C++代码中的性能瓶颈,并改进性能 3、 PureCoverage:发现C/C++代码中未被测试的部分,保证测试的完备性。 3.1.1 PurifyPlus对C/C++代码进行运行时分析的原理和步骤。 C/C++应用的开发过程是首先编译代码成目标文件,然后在连接成可执行文件。如下的makefile所示: # 连接成可执行文件 CC=cc hello: hello.o $(CC) –o hello hel
7、lo.o # comiple成目标文件 hello.obj: hello.c $(CC) –g –c hello.c PurifyPlus进行运行时分析时,要对编译后形成的目标代码进行自动插针,然后再连接形成可执行文件。以用Purify进行内存分析为例,上面的makefile改为: # 连接成可执行文件 CC=cc hello.pure: hello.o purify $(CC) –o hello.pure hello.o # comiple成目标文件 hello.obj: hello.c $(CC) –g –c hello.c 在运行经过插针的h
8、ello.pure后,就能获得运行时分析数据。 3.1.2 利用Purify对C/C++代码进行内存分析 Purify是当今最全面的内存检测工具,在国内得到广泛的应用,几乎是开发高可靠C/C++软件的必备工具之一。它可以检测执行程序的任何部分(如代码、系统库、第三方库)的内存问题,并支持多进程、多线程应用。 Purify通过检测任何内存访问操作,指出内存访问错误的位置,并提供详细的诊断信息帮助分析为什么会产生内存错误。所能检测的错误包括: 1、 内存越界写或读 2、 读取未初始化的内存 3、 读或写被释放的内存 4、 栈内存访问越界 5、 内存泄露或文件句柄未释放 如果编译形
9、成的目标代码包含调试信息,Purify能把内存访问错误定位到代码行,如果不包括调试信息,Purify也能定位到特定的函数和目标文件。 通过Purify,可以快速发现代码中的内存问题,而不是仅仅通过代码评审或调试手段来定位问题。 下图Purify自动发现的内存问题: 指出数组越界读错误 指出错误发生的位置 指出错误引入的位置 内存访问错误的内存位置 指出内存分配的代码 3.1.3 利用PureCoverage对C/C++代码进行执行覆盖分析 通过PureCoverage组件,可以快速发现程序中未被测试的函数、方法和代码行,这样开发人员可以不断丰富测试用例,提高测试完备性。该
10、组件具有如下功能: 1、 指出未被测试的代码 2、 实现多次执行的代码覆盖结果合并 3、 自动生成各种代码覆盖统计报告 4、 在UNIX环境下生成的代码覆盖报告可以在Windows平台下用PureCoverage显示 未被测试代码 未被测试代码 代码行 源代码 代码运 行次数 3.1.4 利用Quantify对C/C++代码进行性能分析 Quantify是PurifyPlus提供的一个强大的性能分析工具,该工具具有如下功能: 1、 得到准确、可靠的性能数据,能统计出每个函数、每行代码的执行时间、执行次数以及耗时比重。 2、 能比较代码调整前后的性能差异。 3、
11、 突出显示潜在的性能瓶颈。 在上图中,Function List显示耗时最多函数的列表和具体消耗的时间,Annotated Source图显示每行代码的消耗时间,Function Detail图显示单个函数的消耗时间以及调用该函数的函数列表和该函数调用的其他函数列表,而Call Graph图显示消耗时间最多的调用。 4 产品平台支持 4.1 PurifyPlus平台支持 产品 操作系统 编译器 PurifyPlus for Windows Windows XP Professional Windows 2000 Professional Windows 2
12、000 Server Windows 2000 Advanced Server Microsoft Server 2003 Standard Edition Microsoft Server 2003 Enterprise Edition, Visual C++ 6.0 Visual Basic 6.0 Visual Studio .NET IBM WebSphere Application Developer 5.0, 5.1.1, 5.1.2 IBM WebSphere Studio WorkBench 2.0, 2.1.2, 2.1.3 PurifyPlus for
13、 Unix & Linux Sun Solaris 2.6, 2.7, 2.8, 2.9, 2.10 Sun One Studio 7, 8, 9, 10 Forte 6 Update 1, 2 Forte 6 (compiler version 5.1) Sun Workshop C and C++ 4.2 and 5.0 GNU gcc and g++ versions 2.8.1, 2.95.X, 3.0.x, 3.1, 3.2, 3.3, 3.4, 3.4.3 Cygnus GNUpro v.98r2 HP-UX 10.20, 11.00, 11.11, 11.2
14、3 Bundled cc ANSI cc up to version B.11.11.06 c++ aCC versions 3.27, 3.30, 3.31, 3.33, 3.34, 3.37, 3.39, 3.45, 3.50, 3.52, 3.55, 3.56 and 3.60. GNU gcc/g++ versions 2.8.1, 2.95.X, 3.0.x, 3.1, 3.2, 3.3, 3.4 (32-bit only) Cygnus GNUpro v.98r2 RedHat Linux 7.2, 7.3, 8.0 RedHat Enterprise Linux 2.1, Linux AS/ES/WS 3.0, 4.0 SUSE LINUX Enterprise Server 8, 9 gcc/g++ 2.96-112 gcc/g++ 2.96-113 gcc/g++ 3.2-7 gcc/g++ 3.2-34 gcc/g++ 3.2.2 gcc/g++ 3.2.3 gcc/g++ 3.3.1 gcc/g++ 3.3.2 gcc/g++ 3.4 gcc/g++ 3.4.3 AIX 5.1, 5.2 and 5.3 xlc/xlC (Visual Age)






