领测软件测试网
-E:i)p2U
r:e+XZH2.尽早发现内存问题
[52RD.com]ANqo!RJc1M!U[52RD.com]-SV5r3F6T"U3[W@[ 内存问题危害很大,不容易排查,主要有三种类型:内存泄露、内存碎片和内存崩溃。对于内存问题态度必须要明确,那就是早发现早“治疗”。在软件设计中,内存泄露的“名气”最大,主要由于不断分配的内存无法及时地被释放,久而久之,系统的内存耗尽。即使细心的编程老手有时后也会遭遇内存泄露问题。有测试过内存泄露的朋友估计都有深刻地体验,那就是内存泄露问题一般隐藏很深,很难通过代码阅读来发现。有些内存泄露甚至可能出现在库当中。有可能这本身是库中的bug,也有可能是因为程序员没有正确理解它们的接口说明文档造成错用。
[52RD.com]xQ"F&ZTF[52RD.com]软件测试技术门户iu!r'by 在很多时候,大多数的内存泄露问题无法探测,但可能表现为随机的故障。程序员们往往会把这种现象怪罪于硬件问题。如果用户对系统稳定性不是很高,那么重启系统问题也不大;但,如果用户对系统稳定很高,那么这种故障就有可能使用户对产品失去信心,同时也意味着你的项目是个失败的项目。由于内存泄露危害巨大,现在已经有许多工具来解决这个问题。这些工具通过查找没有引用或重复使用的代码块、垃圾内存收集、库跟踪等技术来发现内存泄露的问题。每个工具都有利有弊,不过总的来说,用要比不用好。总之,负责的开发人员应该去测试内存泄露的问题,做到防患于未然。
[52RD.com]"h0N.H5PbG)Ic{6z[52RD.com]软件测试技术门户7_|1oR/Uf/n 内存碎片比内存泄露隐藏还要深。随着内存的不断分配并释放,大块内存不断分解为小块内存,从而形成碎片,久而久之,当需要申请大块内存是,有可能就会失败。如果系统内存够大,那么坚持的时间会长一些,但最终还是逃不出分配失败的厄运。在使用动态分配的系统中,内存碎片经常发生。目前,解决这个问题最效的方法就是使用工具通过显示系统中内存的使用情况来发现谁是导致内存碎片的罪魁祸首,然后改进相应的部分。
[52RD.com]g9ns8V*\&Q@){[52RD.com]#JEs$u
l&b
vt 由于动态内存管理的种种问题,在嵌入式应用中,很多公司干脆就禁用malloc/free的以绝后患。
[52RD.com]!Q8V-h+y)u~aK[52RD.com].Q*@:wK
tI| 内存崩溃是内存使用最严重的结果,主要原因有数组访问越界、写已经释放的内存、指针计算错误、访问堆栈地址越界等等。这种内存崩溃造成系统故障是随机的,而且很难查找,目前提供用于排查的工具也很少。
[52RD.com]软件测试技术门户"t"B8s
S7y4@9y.e#D
t[52RD.com]'a:aC-KQf7TM}p 总之,如果要使用内存管理单元的话,必须要小心,并严格遵守它们的使用规则,比如谁分配谁释放。
[52RD.com]-{js,A DfKo[52RD.com]h.z*z^w0?)xR 3.深入理解代码优化
[52RD.com]软件测试技术门户,^|/f-w0Y[52RD.com]软件测试技术门户4Iy1eC}8W 讲到系统稳定性,人们更多地会想到实时性和速度,因为代码效率对嵌入式系统来说太重要了。知道怎么优化代码是每个嵌入式软件开发人员必须具备的技能。就象女孩子减肥一样,起码知道她哪个地方最需要减,才能去购买减肥药或器材来减掉它。可见,代码优化的前提是找到真正需要优化的地方,然后对症下药,优化相应部分的代码。前面提到的profile(性能分析工具,一些功能齐全IDE都提供这种内置的工具)能够记录各种情况比如各个任务的CPU占用率、各个任务的优先级是否分配妥当、某个数据被拷贝了多少次、访问磁盘多少次、是否调用了网络收发的程序、测试代码是否已经关闭等等。
[52RD.com]软件测试技术门户
C|Dyoy&ZA[52RD.com]软件测试技术门户0B*]G"MQ[.Ep![ 但是,profile工具在分析实时系统性能方面还是有不够的地方。一方面,人们使用profile工具往往是在系统出现问题即CPU耗尽之后,而profile工具本身对CPU占用较大,所以profile对这种情况很可能不起作用。根据Heisenberg效应,任何测试手段或多或少都会改变系统运行,这个对profiler同样适用!
[52RD.com]软件测试技术门户 x${7Mu.{~c[52RD.com]软件测试技术门户g EbpfW3F 总之,提高运行效率的前提是你必须要知道CPU到底干了些什么干的怎么样。
[52RD.com]软件测试技术门户 P$R0Ewm?`[52RD.com]8Adw^4FQ 4.不要让自己大海捞针
[52RD.com]g8^BI
T&V+Q\&b&n6IR[52RD.com]软件测试技术门户tr_p&D 大海捞针只是对调试的一种生动比喻。
[52RD.com]软件测试技术门户n'H/o2V'wk4u@.F[52RD.com]yQm4F2X9H 经常听到组里有人对自己正在调试的代码说shit!可以理解,因为代码不是他写的,他有足够的理由去shit bug百出的代码,只要他自己不要写出这种代码,否则有一天同组的其它人可能同样会shit他写的代码。为何会有大海捞针呢?肯定是有人把针掉到海里咯;那针为何会掉在海里呢?肯定是有人不小心或草率呗。所以当你在抱怨针那么难找的时候,你是否想过是你自己草率地丢掉的。同样,当你调试个半死的时候,你是否想过你要好好反省一下当初为了寻求捷径可能没有严格地遵守好的编码设计规范、没有检测一些假设条件或算法的正确性、没有将一些可能存在问题的代码打上记号呢?关于如何写高质量请参考林锐的《高质量c++/c编程指南》或《关于C的0x8本“经书”》。
[52RD.com]软件测试技术门户Qc*P4W,`n$jN[F[52RD.com]:dpK3sWD@s3B'^c 如果你确实已经把针掉在海里是,为了防止在找到之前刺到自己,你必须要做一些防范工作,比如戴上安全手套。同样,为了尽能地暴露和捕捉问题根源,我们可以设计比较全面的错误跟踪代码。怎么来做呢?尽可能对每个函数调用失败作出处理,尽可能检测每个参数输入输出的有效性包括指针以及检测是否过多或过少地调用某个过程。错误跟踪能够让你知道你大概把针掉在哪个位置。
[52RD.com]gK(a0ds\9W[52RD.com]软件测试技术门户 {!X5M%q w 5.重现并隔离问题
[52RD.com]软件测试技术门户'^Q#S1v&u'O E[52RD.com]软件测试技术门户/Q#l$J$?F+yT 如果你不是把针掉在大海了,而是掉在草堆里,那要好办写。因为至少我们可以把草堆分成很多块,一块一块的找。对于模块独立的大型项目,使用隔离方法往往是对付那些隐藏极深bug的最后方法。如果问题的出现是间歇性的,我们有必要设法去重现它并记录使其重现的整个过程以备在下一次可以利用这些条件去重现问题。如果你确信可以使用记录的那些条件去重现问题,那么我们就可以着手去隔离问题。怎么隔离呢?我们可以用#ifdef把一些可能和问题无关的代码关闭,把系统最小化到仍能够重现问题的地步。如果还是无法定位问题所在,那么有必要打开“工具箱”了。可以试着用ICE或数据监视器去查看某个可疑变量的变化;可以使用跟踪工具获得函数调用的情况包括参数的传递;检查内存是否崩溃以及堆栈溢出的问题。
[52RD.com]软件测试技术门户j'l;D:p8J`1h+w#S[52RD.com]A|y?d!g1H;L0ui 6.以退为进
[52RD.com]软件测试技术门户5[+|y"M;~3m"i[52RD.com]c9zG
Q7vZF$X 猎人为了不使自己在森林里迷路,他常常会在树木上流下一些标记,以备自己将来有一天迷路时可以根据这些标记找到出路。对过去代码的修改进行跟踪记录对将来出现问题之后的调试很有帮助。假如有一天,你最近一次修改的程序跑了很久之后忽然死掉了,那么你这时的第一反映就是我到底改动了些什么呢,因为上次修改之前是好的。那么如何检测这次相对于上次的修改呢?没错,代码控制系统SCS或称版本控制系统VCS(Concurrent Version Control,CVS是VCS的演化版本)。将上个版本check in下来后和当前测试版本比较。比较的工具可以是SCS/VCS/CVS自带的diff工具或其它功能更强的比较工具,比如BeyondCompare和ExamDiff。通过比较,记录所有改动的代码,分析所有可能导致问题的可疑代码。
[52RD.com]软件测试技术门户){!j aG2nU)Z[52RD.com]软件测试技术门户:m0T`}a'bP+\4p 7.确定测试的完整性
[52RD.com]@.h+jfR"N[52RD.com]软件测试技术门户:c{{I(p\