总是很难忘记生活的点点滴滴, 脑海中总是闪过好多的曾经, 美好的回忆, 但成长中却让我们失去了很多, 很想在忙碌的生活中淡淡忘记; 不曾放低的东西却始终让我忘记不了, 但我还要在忙碌的生活中继续生活!

发布新日志

  • 软件测试面试题(最新!更新中!)

    2009-09-26 12:05:01

    01. 为什么要在一个团队中开展软件测试工作?
      因为没有经过测试的软件很难在发布之前知道该软件的质量,就好比ISO质量认证一样,测试同样也需要质量的保证,这个时候就需要在团队中开展软件测试的工作。在测试的过程发现软件中存在的问题,及时让开发人员得知并修改问题,在即将发布时,从测试报告中得出软件的质量情况。

    02. 您在以往的测试工作中都曾经具体从事过哪些工作?其中最擅长哪部分工作?
      我曾经做过web测试,后台测试,客户端软件,其中包括功能测试,性能测试,用户体验测试。最擅长的是功能测试

    03. 您所熟悉的软件测试类型都有哪些?请试着分别比较这些不同04. 的测试类型的区别与联系(如功能测试、性能测试……)
      测试类型有:功能测试,性能测试,界面测试。
      功能测试在测试工作中占的比例最大,功能测试也叫黑盒测试。是把测试对象看作一个黑盒子。利用黑盒测试法进行动态测试时,需要测试软件产品的功能,不需测试软件产品的内部结构和处理过程。采用黑盒技术设计测试用例的方法有:等价类划分、边界值分析、错误推测、因果图和综合策略。
      性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。负载测试和压力测试都属于性能测试,两者可以结合进行。通过负载测试,确定在各种工作负载下系统的性能,目标是测试当负载逐渐增加时,系统各项性能指标的变化情况。压力测试是通过确定一个系统的瓶颈或者不能接收的性能点,来获得系统能提供的最大服务级别的测试。
      界面测试,界面是软件与用户交互的最直接的层,界面的好坏决定用户对软件的第一印象。而且设计良好的界面能够引导用户自己完成相应的操作,起到向导的作用。同时界面如同人的面孔,具有吸引用户的直接优势。设计合理的界面能给用户带来轻松愉悦的感受和成功的感觉,相反由于界面设计的失败,让用户有挫败感,再实用强大的功能都可能在用户的畏惧与放弃中付诸东流。
      区别在于,功能测试关注产品的所有功能上,要考虑到每个细节功能,每个可能存在的功能问题。性能测试主要关注于产品整体的多用户并发下的稳定性和健壮性。界面测试更关注于用户体验上,用户使用该产品的时候是否易用,是否易懂,是否规范(快捷键之类的),是否美观(能否吸引用户的注意力),是否安全(尽量在前台避免用户无意输入无效的数据,当然考虑到体验性,不能太粗鲁的弹出警告)?做某个性能测试的时候,首先它可能是个功能点,首先要保证它的功能是没问题的,然后再考虑该功能点的性能测试

    04.您认为做好测试用例设计工作的关键是什么?
    白盒测试用例设计的关键是以较少的用例覆盖尽可能多的内部程序逻辑结果
    黑盒法用例设计的关键同样也是以较少的用例覆盖模块输出和输入接口。不可能做到完全测试,以最少的用例在合理的时间内发现最多的问题


    05.     请试着比较一下黑盒测试、白盒测试、单元测试、集成测试、系统测试、验收测试的区别与联系。

      黑盒测试:已知产品的功能设计规格,可以进行测试证明每个实现了的功能是否符合要求。
      白盒测试:已知产品的内部工作过程,可以通过测试证明每种内部操作是否符合设计规格要求,所有内部成分是否以经过检查。

      软件的黑盒测试意味着测试要在软件的接口处进行。这种方法是把测试对象看做一个黑盒子,测试人员完全不考虑程序内部的逻辑结构和内部特性,只依据程序的需求规格说明书,检查程序的功能是否符合它的功能说明。因此黑盒测试又叫功能测试或数据驱动测试。黑盒测试主要是为了发现以下几类错误:
      1、是否有不正确或遗漏的功能?
      2、在接口上,输入是否能正确的接受?能否输出正确的结果?
      3、是否有数据结构错误或外部信息(例如数据文件)访问错误?
      4、性能上是否能够满足要求?
      5、是否有初始化或终止性错误?

      软件的白盒测试是对软件的过程性细节做细致的检查。这种方法是把测试对象看做一个打开的盒子,它允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例,对程序所有逻辑路径进行测试。通过在不同点检查程序状态,确定实际状态是否与预期的状态一致。因此白盒测试又称为结构测试或逻辑驱动测试。白盒测试主要是想对程序模块进行如下检查:
      1、对程序模块的所有独立的执行路径至少测试一遍。
      2、对所有的逻辑判定,取“真”与取“假”的两种情况都能至少测一遍。
      3、在循环的边界和运行的界限内执行循环体。
      4、测试内部数据结构的有效性,等等。

      单元测试(模块测试)是开发者编写的一小段代码,用于检验被测代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。

      单元测试是由程序员自己来完成,最终受益的也是程序员自己。可以这么说,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。

      集成测试(也叫组装测试,联合测试)是单元测试的逻辑扩展。它的最简单的形式是:两个已经测试过的单元组合成一个组件,并且测试它们之间的接口。从这一层意义上讲,组件是指多个单元的集成聚合。在现实方案中,许多单元组合成组件,而这些组件又聚合成程序的更大部分。方法是测试片段的组合,并最终扩展进程,将您的模块与其他组的模块一起测试。最后,将构成进程的所有模块一起测试。

      系统测试是将经过测试的子系统装配成一个完整系统来测试。它是检验系统是否确实能提供系统方案说明书中指定功能的有效方法。(常见的联调测试)

      系统测试的目的是对最终软件系统进行全面的测试,确保最终软件系统满足产品需求并且遵循系统设计。

      验收测试是部署软件之前的最后一个测试操作。验收测试的目的是确保软件准备就绪,并且可以让最终用户将其用于执行软件的既定功能和任务。
    验收测试是向未来的用户表明系统能够像预定要求那样工作。经集成测试后,已经按照设计把所有的模块组装成一个完整的软件系统,接口错误也已经基本排除了,接着就应该进一步验证软件的有效性,这就是验收测试的任务,即软件的功能和性能如同用户所合理期待的那样。

    06. 测试计划工作的目的是什么?测试计划工作的内容都包括什么?其中哪些是最重要的?
      软件测试计划是指导测试过程的纲领性文件,包含了产品概述、测试策略、测试方法、测试区域、测试配置、测试周期、测试资源、测试交流、风险分析等内容。借助软件测试计划,参与测试的项目成员,尤其是测试管理人员,可以明确测试任务和测试方法,保持测试实施过程的顺畅沟通,跟踪和控制测试进度,应对测试过程中的各种变更。
    测试计划和测试详细规格、测试用例之间是战略和战术的关系,测试计划主要从宏观上规划测试活动的范围、方法和资源配置,而测试详细规格、测试用例是完成测试任务的具体战术。所以其中最重要的是测试测试策略和测试方法(最好是能先评审)

    07. 您认为做好测试计划工作的关键是什么?
      1. 明确测试的目标,增强测试计划的实用性
      编写软件测试计划得重要目的就是使测试过程能够发现更多的软件缺陷,因此软件测试计划的价值取决于它对帮助管理测试项目,并且找出软件潜在的缺陷。因此,软件测试计划中的测试范围必须高度覆盖功能需求,测试方法必须切实可行,测试工具并且具有较高的实用性,便于使用,生成的测试结果直观、准确
      2.坚持“5W”规则,明确内容与过程
      “5W”规则指的是“What(做什么)”、“Why(为什么做)”、“When(何时做)”、“Where(在哪里)”、“How(如何做)”。利用“5W”规则创建软件测试计划,可以帮助测试团队理解测试的目的(Why),明确测试的范围和内容(What),确定测试的开始和结束日期(When),指出测试的方法和工具(How),给出测试文档和软件的存放位置(Where)。
      3.采用评审和更新机制,保证测试计划满足实际需求
    测试计划写作完成后,如果没有经过评审,直接发送给测试团队,测试计划内容的可能不准确或遗漏测试内容,或者软件需求变更引起测试范围的增减,而测试计划的内容没有及时更新,误导测试执行人员。
      4. 分别创建测试计划与测试详细规格、测试用例
      应把详细的测试技术指标包含到独立创建的测试详细规格文档,把用于指导测试小组执行测试过程的测试用例放到独立创建的测试用例文档或测试用例管理数据库中。测试计划和测试详细规格、测试用例之间是战略和战术的关系,测试计划主要从宏观上规划测试活动的范围、方法和资源配置,而测试详细规格、测试用例是完成测试任务的具体战术。

    08. 您所熟悉的测试用例设计方法都有哪些?请分别以具体的例子来说明这些方法在测试用例设计工作中的应用。
      1.等价类划分
      划分等价类: 等价类是指某个输入域的子集合.在该子集合中,各个输入数据对于揭露程序中的错误都是等效的.并合理地假定:测试某等价类的代表值就等于对这一类其它值的测试.因此,可以把全部输入数据合理划分为若干等价类,在每一个等价类中取一个数据作为测试的输入条件,就可以用少量代表性的测试数据.取得较好的测试结果.等价类划分可有两种不同的情况:有效等价类和无效等价类.

      2.边界值分析法
      边界值分析方法是对等价类划分方法的补充。测试工作经验告诉我,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入输出范围的内部.因此针对各种边界情况设计测试用例,可以查出更多的错误.
      使用边界值分析方法设计测试用例,首先应确定边界情况.通常输入和输出等价类的边界,就是应着重测试的边界情况.应当选取正好等于,刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据.

    3.错误推测法
      基于经验和直觉推测程序中所有可能存在的各种错误, 从而有针对性的设计测试用例的方法.
      错误推测方法的基本思想: 列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据他们选择测试用例. 例如, 在单元测试时曾列出的许多在模块中常见的错误. 以前产品测试中曾经发现的错误等, 这些就是经验的总结. 还有, 输入数据和输出数据为0的情况. 输入表格为空格或输入表格只有一行. 这些都是容易发生错误的情况. 可选择这些情况下的例子作为测试用例.

    4.因果图方法
      前面介绍的等价类划分方法和边界值分析方法,都是着重考虑输入条件,但未考虑输入条件之间的联系, 相互组合等. 考虑输入条件之间的相互组合,可能会产生一些新的情况. 但要检查输入条件的组合不是一件容易的事情, 即使把所有输入条件划分成等价类,他们之间的组合情况也相当多. 因此必须考虑采用一种适合于描述对于多种条件的组合,相应产生多个动作的形式来考虑设计测试用例. 这就需要利用因果图(逻辑模型). 因果图方法最终生成的就是判定表. 它适合于检查程序输入条件的各种组合情况.

    09. 请以您以往的实际工作为例,10. 详细的描述一次测试用例设计的完整的过程。
      就说最近的这次网站功能的测试吧
      首先:得到相关文档(需求文档和设计文档),理解需求和设计设计思想后,想好测试策略(测试计划简单点就OK了),考虑到测试环境,测试用例,测试时间等问题。
      第二步:设计测试用例,测试策略是:把网站部分的功能点测试完,然后在进行系统测试(另外个模块呢有另一个测试人员负责,可以进行联调测试),网站模块的测试基本是功能测试和界面测试(用户并发的可能性很小,所以不考虑):这次的网站的输入数据呢是使用数据库中的某张表记录,如果表中某一数据记录中新加进来的(还没有被处理的,有个标志位),网站启动后会立刻去刷那张表,得到多条数据,然后在进行处理。处理过程中,会经历3个步骤,网站才算完成了它的任务。有3个步骤呢,就可以分别对  这3个步骤进行测试用例的设计,尽量覆盖到各种输入情况(包括数据库中的数据,用户的输入等),得出了差不多50个用例。界面测试,也就是用户看的到的地方,包括发送的邮件和用户填写资料的页面展示。
      第三步:搭建测试环境(为什么这个时候考虑测试环境呢?因为我对网站环境已经很熟了,只有有机器能空于下来做该功能测试就可以做了),因为网站本身的环境搭建和其他的系统有点不同,它需要的测试环境比较麻烦,需要web服务器(Apache,tomcat),不过这次需求呢,网站部分只用到了tomcat,所以只要有tomcat即可
      第四步:执行测试

    11. 您以往是否曾经从事过性能测试工作?如果有,12. 请尽可能的详细描述您以往的性能测试工作的完整过程。
      是的,曾经做过网站方面的性能测试,虽然做的时间并不久(2个月吧),当时呢,是有位网站性能测试经验非常丰富的前辈带着我一起做。
    性能测试类型包括负载测试,强度测试,容量测试等
      负载测试:负载测试是一种性能测试指数据在超负荷环境中运行,程序是否能够承担。
      强度测试: 强度测试是一种性能测试,他在系统资源特别低的情况下软件系统运行情况
      容量测试:确定系统可处理同时在线的最大用户数  
      在网站流量逐渐加大的情况下,开始考虑做性能测试了,首先要写好性能测试计划,根据运营数据得出流量最大的页面(如果是第一次的话,一般是首页,下载页,个人帐户页流量最大,而且以某种百分比),

      Web服务器指标指标:
      * Avg Rps: 平均每秒钟响应次数=总请求时间 / 秒数;
      * Successful Rounds:成功的请求;
      * Failed Rounds :失败的请求;
      * Successful Hits :成功的点击次数;
      * Failed Hits :失败的点击次数;
      * Hits Per Second :每秒点击次数;
      * Successful Hits Per Second :每秒成功的点击次数;
      * Failed Hits Per Second :每秒失败的点击次数;
      * Attempted Connections :尝试链接数;  

    13. 您在从事性能测试工作时,14. 是否使用过一些测试工具?如果有,15. 请试述该工具的工作原理,16. 并以一个具体的工作中的例子描述该工具是如何在实际工作中应用的。

    17. 您认为性能测试工作的目的是什么?做好性能测试工作的关键是什么?

    18. 在您以往的工作中,19. 一条软件缺陷(或者叫Bug)记录都包含了哪些内容?如何提交高质量的软件缺陷(Bug)记录?

    20. 您以往所从事的软件测试工作中,21. 是否使用了一些工具来进行软件缺陷(Bug)的管理?如果有,22. 请结合该工具描述软件缺陷(Bug)跟踪管理的流程。

    23. 您认为在测试人员同24. 开发人员的沟通过程中,25. 如何提高沟通的效率和改善沟通的效果?维持测试人员同26. 开发团队中其他成员良好的人际关系的关键是什么?

    27. 在您以往的测试工作中,28. 最让您感到不29. 满意或者不30. 堪回首的事情是什么?您是如何来对待这些事情的?

    31. 在即将完成这次笔试前,32. 您是否愿意谈一些自己在以往的学习和工作中获得的工作经验和心得体会?(可以包括软件测试、过程改进、软件开发或者与此无关的其他方面)

    33.        你对测试最大的兴趣在哪里?为什么?
      最大的兴趣就是测试有难度,有挑战性!做测试越久越能感觉到做好测试有多难。曾经在无忧测试网上看到一篇文章,是关于如何做好一名测试工程师。一共罗列了11,12点,有部分是和人的性格有关,有部分需要后天的努力。但除了性格有关的1,2点我没有把握,其他点我都很有信心做好它。
      刚开始进入测试行业时,对测试的认识是从无忧测试网上了解到的一些资料,当时是冲着做测试需要很多技能才能做的好,虽然入门容易,但做好很难,比开发更难,虽然当时我很想做开发(学校专业课我基本上不缺席,因为我喜欢我的专业),但看到测试比开发更难更有挑战性,想做好测试的意志就更坚定了。
      不到一年半的测试工作中,当时的感动和热情没有减退一点(即使环境问题以及自身经验,技术的不足,做测试的你一定也能理解)。
      我觉得做测试整个过程中有2点让我觉得很有难度(对我来说,有难度的东西我就非常感兴趣),第一是测试用例的设计,因为测试的精华就在测试用例的设计上了,要在版本出来之前,把用例写好,用什么测试方法写?(也就是测试计划或测试策略),如果你刚测试一个新任务时,你得花一定的时间去消化业务需求和技术基础,业务需求很好理解(多和产品经理和开发人员沟通就能达到目的),而技术基础可就没那么简单了,这需要你自觉的学习能力,比如说网站吧,最基本的技术知识你要知道网站内部是怎么运作的的,后台是怎么响应用户请求的?测试环境如何搭建?这些都需要最早的学好。至少在开始测试之前能做好基本的准备,可能会遇到什么难题?需求细节是不是没有确定好?这些问题都能在设计用例的时候发现。
      第二是发现BUG的时候了,这应该是测试人员最基本的任务了,一般按测试用例开始测试就能发现大部分的bug,还有一部分bug需要测试的过程中更了解所测版本的情况获得更多信息,补充测试用例,测试出bug。还有如何发现bug?这就需要在测试用例有效的情况下,通过细心和耐心去发现bug了,每个用例都有可能发现bug,每个地方都有可能出错,所以测试过程中思维要清晰(测试过程数据流及结果都得看仔细了,bug都在里面发现的)。如何描述bug也很有讲究,bug在什么情况下会产生,如果条件变化一点点,就不会有这个bug,以哪些最少的操作步骤就能重现这个bug,这个bug产生的规律是什么?如果你够厉害的话,可以帮开发人员初步定位问题。

    34. 你的测试职业发展是什么?
      测试经验越多,测试能力越高。所以我的职业发展是需要时间累积的,一步步向着高级测试工程师奔去。而且我也有初步的职业规划,前3年累积测试经验,按如何做好测试工程师的11,12点要求自己,不断的更新自己改正自己,做好测试任务。

    35. 你自认为测试的优势在哪里?
      优势在于我对测试坚定不移的信心和热情,虽然经验还不够,但测试需要的基本技能我有信心在工作中得以发挥。

    36. 你以前工作时的测试流程是什么?
      公司对测试流程没有规定如何做,但每个测试人员都有自己的一套测试流程。我说下我1年来不断改正(自己总结,吸取同行的方法)后的流程吧。需求评审(有开发人员,产品经理,测试人员,项目经理)->需求确定(出一份确定的需求文档)->开发设计文档(开发人员在开始写代码前就能输出设计文档)->想好测试策略,写出测试用例->发给开发人员和测试经理看看(非正式的评审用例)->接到测试版本->执行测试用例(中间可能会补充用例)->提交bug(有些bug需要开发人员的确定(严重级别的,或突然发现的在测试用例范围之外的,难以重现的),有些可以直接录制进TD)->开发人员修改(可以在测试过程中快速的修改)->回归测试(可能又会发现新问题,再按流程开始跑)。

    37. 当开发人员说不38. 是BUG时,39. 你如何应付?
      开发人员说不是bug,有2种情况,一是需求没有确定,所以我可以这么做,这个时候可以找来产品经理进行确认,需不需要改动,3方商量确定好后再看要不要改。二是这种情况不可能发生,所以不需要修改,这个时候,我可以先尽可能的说出是BUG的依据是什么?如果被用户发现或出了问题,会有什么不良结果?程序员可能会给你很多理由,你可以对他的解释进行反驳。如果还是不行,那我可以给这个问题提出来,跟开发经理和测试经理进行确认,如果要修改就改,如果不要修改就不改。其实有些真的不是bug,我也只是建议的方式写进TD中,如果开发人员不修改也没有大问题。如果确定是bug的话,一定要坚持自己的立场,让问题得到最后的确认。

    23.你为什么想离开目前的职务?
      因为公司运作情况并不理想,公司需要调整部门体系,公司考虑到缩减部门人员,所以大批量的裁员(有6,7个),这是我的第一份工作,对公司也有较深的感情,因为在这里我找到了职业理想(就是测试),所以公司需要精简人员,我自愿退出。虽然很舍不得,但我将会有新的发挥能力的舞台。

    24:你对我们公司了解有多少?

    25:你找工作时,最重要的考虑因素为何?
      工作的性质和内容是否能让我发挥所长,并不断成长。

    26:为什么我们应该录取你?
      您可以由我过去的工作表现所呈现的客观数据,明显地看出我全力以赴的工作态度。

    27:请谈谈你个人的最大特色。
      我的坚持度很高,事情没有做到一个令人满意的结果,绝不罢手。

    28.白箱测试和黑箱测试是什么?什么是回归测试?

    29。单元测试、集成测试、系统测试的侧重点是什么?

    30。设计用例的方法、依据有那些?

    31。一个测试工程师应具备那些素质和技能?

    32.集成测试通常都有那些策略?

    33.你用过的测试工具的主要功能、性能及其他?

    34.一个缺陷测试报告的组成

    35.基于WEB信息管理系统测试时应考虑的因素有哪些?

    36.软件测试项目从什么时候开始,?为什么?

    37.需求测试注意事项有哪些?

    38.简述一下缺陷的生命周期

    39.测试分析测试用例注意(事项)?
      你在你所在的公司是怎么开展测试工作的?是如何组织的?
      你认为理想的测试流程是什么样子?
      你是怎样工作的?
      软件测试活动的生命周期是什么?
      请画出软件测试活动的流程图?
      针对缺陷采取怎样管理措施?
      什么是测试评估?测试评估的范围是什么?
      如果能够执行完美的黑盒测试,还需要进行白盒测试吗?为什么?
      测试结束的标准是什么?
      软件验收测试除了alpha,beta测试以外,还有哪一种?
      做测试多久了?
      以前做过哪些项目?
      你们以前测试的流程是怎样的?
      <答:测试计划-测试用例设计-测试执行-测试分析报告>
      用过哪些测试工具?
      为什么选择测试这行?
      <答:它是一个新兴的行业,有发展潜力,而且很锻炼人,需要掌握更多的技能,比做开发要更难>
      为什么值得他们公司雇用?
      如果我雇用你,你能给部门带来什么贡献?
      如何从工作中看出你是个自动自觉的人
      你的工作通常能在时限内完成吗.(我想问一下就是她问这个问题的动机是什么)
      通常你对于别人批评你会有什么样的反应
      如果明知这样做不对,你还会依主管的指过去做吗
      如果你接到一个客户抱怨的电话,你确知无法解决他的问题,你会怎么处理
      你觉得什么样的人最难相处
      为什么值得他们公司雇用?
        帮助公司提高软件质量和测试部门的技术水平
      如果我雇用你,你能给部门带来什么贡献?
        分享我的测试经验和测试技能,提高测试部门技术水平
      如何从工作中看出你是个自动自觉的人
               自动自觉范围太广
            1. 工作成果
            2. 工作质量 
      你的工作通常能在时限内完成吗.(我想问一下就是她问这个问题的动机是什么)
        在有足够的资源和合理的工作量的情况下,完全可以按时完成,并能比一般人做的更好
      通常你对于别人批评你会有什么样的反应
        有错即改,无措勉之

      如果明知这样做不对,你还会依主管的指过去做吗
        在公司内部下级是否有申诉渠道?

      如果你接到一个客户抱怨的电话,你确知无法解决他的问题,你会怎么处理
        为什么抱怨?是怎么样的问题?
        如果是客服问题,提交客服部门解决
        如果是质量问题,分析原因,下一版本改进
      你觉得什么样的人最难相处
        自以为是的人

      什么叫单元测试?
        请就软件测试人员应该具备什么样的基本素质说说你的看法。

      请就如何在开发中进行软件质量控制说说你的看法
       简述软件测试的意义,以及软件测试的分类

    1、功能测试,性能测试,界面测试,安全测试(可以简单点,比如只涉及到COOKIES里的内容),压力测试(商业性质的网站) 等等,B/S软件也要根据其具体功能采用不同的测试策略。
    2、态度、责任心、自信、敏锐的观察力、良好的发散思维
    3、先设计后开发模式,加强单元测试,加强代码走查,有一套完整的白盒测试方法。关键是加强开发人员的质量意识,增进程序员向工程师水平发展。
    4、意义嘛,就自己想吧。软件测试的分类,这个很多人都按各种方法去分。无明确答案给你。

    对测试的理解——基本的测试知识,对测试是否认可? 75。
          3、谈一谈过去自己的工作——了解经历、提供进一步提问的素材,表达能力  
    测试技能
    测试设计的方法并举例说明——测试技术的使用
    测试工具——熟悉程度,能否与当前工作匹配?
    如何做计划?如何跟踪计划?——日常工作能力
    如果开发人员提供的版本不满足测试的条件,如何做?——与开发人员协作的能力
    熟悉unix系统、oracle数据库吗?——是否具备系统知识
    做过开发吗?写过哪些代码?——开发技能
    阅读英语文章,给出理解说明?——部分英语能力
    文档的意义——是否善于思考?(最简单的概念,不同层次的理解)
    假如进入我们公司,对我们哪些方面会有帮助?——讲讲自己的特长
    随便找一件物品,让其测试——测试的实际操作能力
    软件测试的方法有?
    软件测试的过程?
    有一个新的软件,假如你是测试工程师,该如何做?

    软件测试分哪两种方法?分别适合什么情况?
    2。一套完整的测试应该由哪些阶段组成?分别阐述一下各个阶段。
    3。软件测试的类型有那些?分别比较这些不同的测试类型的区别与联系。
    4。测试用例通常包括那些内容?着重阐述编制测试用例的具体做法
    5。在分别测试winform的C/S结构与测试WEB结构的软件是,应该采取什么样的方法分别测试?他们存在什么样的区别与联系?
    6。在测试winform的C/S结构软件时,发现这个软件的运行速度很慢,您会认为是什么原因?您会采取哪些方法去检查这个原因?
    7。描述使用bugzilla缺陷管理工具对软件缺陷(BUG)跟踪的管理的流程
    你在五年内的个人目标和职业目标分别是什么?
      分析这个问题是用来了解你的计划能力的,通过这个问题,面试人同时还可以知道你的目标是否符合企业对你的安排。
      错误回答我想在将来的某个时候考虑这个问题。如今企业的领导者更换频繁,我认为做太多的个人计划是荒谬可笑的,不是吗?
      评论这种回答属于令人反感的一类。首先,当有人想了解你的目标时,"将来的某个时候"这种通俗说法并不奏效。其次,认为企业很脆弱,领导者更换频繁,这种说法毫无疑问会令人反感,而且也是不合理的。最后,认为做计划可笑,看不起这个问题,而且反问面试人,这些都注定了这样的求职者最终会失败。
      正确回答从现在起的五年之内,我希望能够在一个很好的职位上待几年,而且最好有一次晋升,然后就期待着下一步。不管是向上提升,还是在企业内横向调动,对我个人来说,我希望找到一家企业——一家愿意做相互投入的企业——待上一段时间。
      评论这个问题没有回答得过分具体(那样可能会产生漏洞),而且它表明你有雄心,并且思考过在企业中的成长方式。通过表达横向调动和向上提升的愿望,表明你是一个有灵活性的人。
     问题23 你怎样做出自己的职业选择?
      分析 面试人提出这个问题是为了了解求职者的动机,看看他(她)应聘这份工作是否有什么历史渊源,是否有职业规划,是不是仅仅在漫无目的地申请很多工作。
      错误回答 我一直都想在企业界工作。自孩提时代起,我就梦想自己至少也要成为大企业的副总裁。
      评论 除了难以令人相信之外,这种回答还存在一个问题:它表明求职者会对副总裁以下的职位不感兴趣。
      正确回答 在上大学四年级前的那个夏天,我决定集中精力在某一领域谋求发展。尽管我是学商业的,但是我不知道自己最终会从事哪一行业的工作。我花了一定的时间考虑自己的目标,想清楚了自己擅长做的事情以及想从工作中得到的东西,最后我得出了一个坚定的结论,那就是这个行业是最适合我的。
      评论 这种回答表明,求职者认真地做过一些计划,缩小了自己的关注点,而且也认准了前进的方向。这种回答还表明,求职者理解个人职业规划的重要性,并且有能力做出认真的个人决策。
    1. 你都用什么测试方法
    2.怎么编写案例
    3.怎么才能够全面的测试到每一个点
    1. 你都用什么测试方法
    针对不同的产品或者系统或者模块,有不同的测试方法。总体而言有白盒测试和黑盒测试。
    2.怎么编写案例
    案例的编写与测试阶段的定义有很大的关系。系统测试和unit测试的案例可能不同。总体而言测试案例根据系统的需求而定。
    3.怎么才能够全面的测试到每一个点
    测试的全面性主要需要在设计测试计划的时候考虑,从测试策略,产品需求等等多个角度考虑从而定义全部的测试点。
    1、谈谈软件测试技术,以及如何提高
    2、谈谈软件测试职业发展,以及个人的打算
    3、谈谈软件测试在企业的地位,也可以结合软件生命周期来谈
    有可能清晰的思路比确切的答案更重要
    在这里,主要说下笔试和面试的问题,希望大家共同参考。
           1,一般公司里实际的软件测试流程是什么样的?你们公司又是怎样的?
           2,软件工程师要具有那些素质?
           3,你会哪些测试工具?怎么操作?
           4,你能不能说下你的3到5年的职业计划(规划)
           5,你觉得你来应聘有那些优势?
    其余的还好说,但就第4个问题,我感到不好说哦!希望大家给个意见
    第一关:首先要自我介绍,自己的性格怎么样,目前的工作经历积累了一些什么经验取得了些什么值得一说的成果。然后要说说对软件测试怎么看?还有对于软件测试有什么自己的想法。为什么会想到要做这行(因为我的简历上的工作经历没有关于测试方面的)。哦,还有期望薪资。
    第二关:认为软件测试人员所要具备的基本素质,如果遇到问题会怎样处理,如果得不到研发人员的配合(就是研发说这个不是问题)你又会怎么处理?然后就是一些基本概念,比如软件测试的流程有哪些?如果我上任了,首先会怎么开始自己的工作计划。
    (前两关通过了后面这个就好过多了)
    第三关:像我介绍了一下公司的情况,告诉我主要针对什么内容的测试,会不会使用数据库。告诉我大概要做哪些内容,详细的可以上岗以后慢慢熟悉。
    大概就这么多了,这对没有经过这一关的不知道有没有帮助,仅供参考吧
    我觉得就像李波说的,关键是要给对方留下好印象:)

    面试官最后会问你有什么问题要问吗。作为应聘者的你一般不要说没问题问,这会给面试官留下你不太重视这份工作的坏印象。所以如果你想得到这份工作的话应该抓住这最后的表现自己的机会:
    你可以问:
    1.           贵公司近期和远期的发展目标是什么?
    2.           贵公司的主要竞争对手有哪些?
    3.           贵公司有多少开发人员有多少测试人员?
    4.           贵公司又进一步扩充测试人员的计划吗?
    5.           如果我有幸能进入贵公司的话,我有怎么样的发展?
    6.           测试人员的沟通能力很重要,贵公司有规范的沟通渠道吗?
    7.           请介绍一下贵公司的福利情况。
    8.           请问我什么时候能知道结果?

  • 嵌入式软件测试的10大秘诀

    2009-07-30 18:21:15

    嵌入式软件测试的10大秘诀

    摘要  1.懂得使用工具;2.尽早发现内存问题;3.深入理解代码优化;4.不要让自己大海捞针;5.重现并隔离问题;6.以退为进;7.确定测试的完整性;8.提高代码质量意味着节省时间;9.发现它,分析它,解决它;10.利用初学者的思维

      在嵌入式软件开发过程中,一般来说,花在测试和花在编码的时间比为3:1(实际上可能更多)。这个比例随着你的编程和测试水平的提高而不断下降,但不论怎样,软件测试对一般人来讲很重要。很多年前,一位开发人员为了对嵌入式有更深层次的理解,向Oracle询问了这样的一个问题:我怎么才能知道并懂得我的系统到底在干些什么呢 Oracle面对这个问题有些吃惊,因为在当时没有人这么问过,而同时代的嵌入式开发人员问的最多的大都围绕“我怎么才能使程序跑的更快”、“什么编译器最好”等肤浅的问题。所以,面对这个不同寻常却异乎成熟的问题,Oracle感到欣喜并认真回复了他:你的问题很有深度很成熟,因为只有不断地去深入理解才有可能不断地提高水平。并且Oracle为了鼓励这位执着的程序员,把10条关于嵌入式软件开发测试的秘诀告诉了他:

    1.懂得使用工具
    2.尽早发现内存问题
    3.深入理解代码优化
    4.不要让自己大海捞针
    5.重现并隔离问题
    6.以退为进
    7.确定测试的完整性
    8.提高代码质量意味着节省时间
    9.发现它,分析它,解决它
    10.利用初学者的思维
      这十条秘诀在业界广为流传,使很多人受益。本文围绕这十条秘诀展开论述。

    1.懂得使用工具

       通常嵌入式系统对可靠性的要求比较高。嵌入式系统安全性的失效可能会导致灾难性的后果,即使是非安全性系统,由于大批量生产也会导致严重的经济损失。这就要求对嵌入式系统,包括嵌入式软件进行严格的测试、确认和验证。随着越来越多的领域使用软件和微处理器控制各种嵌入式设备,对门益复杂的嵌入式软件进行快速有效的测试愈加显得重要。

       就象修车需要工具一样,好的程序员应该能够熟练运用各种软件工具。不同的工具,有不同的使用范围,有不同的功能。使用这些工具,你可以看到你的系统在干些什么,它又占用什么资源,它到底和哪些外界的东西打交道。让你郁闷好几天的问题可能通过某个工具就能轻松搞定,可惜你就是不知道。那么为什么那么多的人总是在折腾个半死之后才想到要用测试工具呢?原因很多,主要有两个。一个是害怕,另一个是惰性。害怕是因为加入测试用具或测试模块到代码需要技巧同时有可能引入新的错误,所以他们总喜欢寄希望于通过不断地修改重编译代码来消除bug,结果却无济于事。懒惰是因为他们习惯了使用printf之类的简单测试手段。下面来介绍一些嵌入式常用的测试工具。

    .源码级调试器[Source-level Debugger]

    这种调试器一般提供单步或多步调试、断点设置、内存检测、变量查看等功能,是嵌入式调试最根本有效的调试方法。比如VxWorks TornadoII提供的gdb就属于这一种。

    .简单实用的打印显示工具[printf]

    printf或其它类似的打印显示工具估计是最灵活最简单的调试工具。打印代码执行过程中的各种变量可以让你知道代码执行的情况。但是,printf对正常的代码执行干扰比较大(一般printf占用CPU比较长的时间),需要慎重使用,最好设置打印开关来控制打印。

    .ICE或JTAG调试器[In-circuit Emulator]

    ICE是用来仿真CPU核心的设备,它可以在不干扰运算器的正常运行情况下,实时的检测CPU的内部工作情况。像桌面调试软件所提供的:复杂的条件断点、先进的实时跟踪、性能分析和端口分析这些功能,它也都能提供。ICE一般都有一个比较特殊的CPU,称为外合(bond-out)CPU。这是一种被打开了封装的CPU,并且通过特殊的连接,可以访问到CPU的内部信号,而这些信号,在CPU被封装时,是没法“看到”的。当和工作站上强大的调试软件联合使用时,ICE就能提供你所能找到的最全面的调试功能。但ICE同样有一些缺点:昂贵;不能全速工作;同样,并不是所有的CPU都可以作为外合CPU的,从另一个角度说,这些外合CPU也不大可能及时的被新出的CPU所更换。JTAG(Joint Test Action Group)虽然它最初开发出来是为了监测IC和电路连接,但是这种串行接口扩展了用途,包括对调试的支持。AD公司为Blackfin设计的 Visual Dsp++就支持高速的JTAG调试。

    .ROM监视器[ROM Monitor]

    ROM监控器是一小程序,驻留在嵌入系统ROM中,通过串行的或网络的连接和运行在工作站上的调试软件通信。这是一种便宜的方式,当然也是最低端的技术。它除了要求一个通信端口和少量的内存空间外,不需要其它任何专门的硬件。并提供了如下功能:下载代码、运行控制、断点、单步步进、以及观察、修改寄存器和内存。因为ROM监控器是操作软件的一部分,只有当你的应用程序运行时,它才会工作。如果你想检查CPU和应用程序的状态,你就必须停下应用程序,再次进入ROM监控器。

    .Data监视器[Data Monitor]

    这种监视器在不停止CPU运行的情况下不仅可以显示指定变量内容,还可以收集并以图形形式显示各个变量的变化过程。

    .OS监视器[Operating System Monitor]

    操作系统监视器可以显示诸如任务切换、信号量收发、中断等事件。一方面,这些监视器能够为你呈现事件之间的关系和时间联系;另一方面,还可以提供对信号量优先级反转、死锁和中断延时等问题的诊断。

    .性能分析工具[Profiler]

    可以用来测试CPU到底耗在那里。profiler工具可以让你知道系统的瓶颈在那里、CPU的使用率以及需要优化的地方。

    .内存测试工具[Memory Teseter]

    可以找到内存使用的问题所在,比如内存泄露、内存碎片、内存崩溃等问题。如果发现系统出现一些不可预知的或间歇性的问题,就应该使用内存测试工具测测看。

    .运行跟踪器[Execution Tracer]

    可以显示CPU执行了哪些函数、谁在调用、参数是什么、何时调用等情况。这种工具主要用于测试代码逻辑,可以在大量的事件中发现异常的那些。

    .覆盖工具[Coverage Tester]

    主要显示CPU具体执行了那些代码,并让你知道那些代码分支没有被执行到。这样有助于提高代码质量并消除无用代码。

    .GUI测试工具[GUI Tester]

    很多嵌入式应用带有某种形式的图形用户界面进行交互,有些系统性能测试足根掘用户输入响应时间进行的。GUI测试工具可以作为脚本工具有开发环境中运行测试用例,其功能包括对操作的记录和回放、抓取屏幕显示供以后分析和比较、设置和管理测试过程(Rational公司的robot和Mercury的 Loadrunner工具是杰出的代表)。很多嵌入式设备没有GUI,但常常可以对嵌入式设备进行插装来运行GUI测试脚本,虽然这种方式可能要求对被测代码进行更改,但是节省了功能测试和回归测试的时间。

    .自制工具[Home-made tester]

    在嵌入式应用中,有时候为了特定的目的,需要自行编写一些工具来达到某种测试目的。本人曾经编写的视频流录显工具在测试视频会议数据流向和变化上帮了大忙,帮公司找到了几个隐藏很深的bug

    2.尽早发现内存问题

       内存问题危害很大,不容易排查,主要有三种类型:内存泄露、内存碎片和内存崩溃。对于内存问题态度必须要明确,那就是早发现早“治疗”。在软件设计中,内存泄露的“名气”最大,主要由于不断分配的内存无法及时地被释放,久而久之,系统的内存耗尽。即使细心的编程老手有时后也会遭遇内存泄露问题。有测试过内存泄露的朋友估计都有深刻地体验,那就是内存泄露问题一般隐藏很深,很难通过代码阅读来发现。有些内存泄露甚至可能出现在库当中。有可能这本身是库中的bug,也有可能是因为程序员没有正确理解它们的接口说明文档造成错用。

       在很多时候,大多数的内存泄露问题无法探测,但可能表现为随机的故障。程序员们往往会把这种现象怪罪于硬件问题。如果用户对系统稳定性不是很高,那么重启系统问题也不大;但,如果用户对系统稳定很高,那么这种故障就有可能使用户对产品失去信心,同时也意味着你的项目是个失败的项目。由于内存泄露危害巨大,现在已经有许多工具来解决这个问题。这些工具通过查找没有引用或重复使用的代码块、垃圾内存收集、库跟踪等技术来发现内存泄露的问题。每个工具都有利有弊,不过总的来说,用要比不用好。总之,负责的开发人员应该去测试内存泄露的问题,做到防患于未然。

       内存碎片比内存泄露隐藏还要深。随着内存的不断分配并释放,大块内存不断分解为小块内存,从而形成碎片,久而久之,当需要申请大块内存是,有可能就会失败。如果系统内存够大,那么坚持的时间会长一些,但最终还是逃不出分配失败的厄运。在使用动态分配的系统中,内存碎片经常发生。目前,解决这个问题最效的方法就是使用工具通过显示系统中内存的使用情况来发现谁是导致内存碎片的罪魁祸首,然后改进相应的部分。

       由于动态内存管理的种种问题,在嵌入式应用中,很多公司干脆就禁用malloc/free的以绝后患。

       内存崩溃是内存使用最严重的结果,主要原因有数组访问越界、写已经释放的内存、指针计算错误、访问堆栈地址越界等等。这种内存崩溃造成系统故障是随机的,而且很难查找,目前提供用于排查的工具也很少。

       总之,如果要使用内存管理单元的话,必须要小心,并严格遵守它们的使用规则,比如谁分配谁释放。

    3.深入理解代码优化

       讲到系统稳定性,人们更多地会想到实时性和速度,因为代码效率对嵌入式系统来说太重要了。知道怎么优化代码是每个嵌入式软件开发人员必须具备的技能。就象女孩子减肥一样,起码知道她哪个地方最需要减,才能去购买减肥药或器材来减掉它。可见,代码优化的前提是找到真正需要优化的地方,然后对症下药,优化相应部分的代码。前面提到的profile(性能分析工具,一些功能齐全IDE都提供这种内置的工具)能够记录各种情况比如各个任务的CPU占用率、各个任务的优先级是否分配妥当、某个数据被拷贝了多少次、访问磁盘多少次、是否调用了网络收发的程序、测试代码是否已经关闭等等。

       但是,profile工具在分析实时系统性能方面还是有不够的地方。一方面,人们使用profile工具往往是在系统出现问题即CPU耗尽之后,而profile工具本身对CPU占用较大,所以profile对这种情况很可能不起作用。根据Heisenberg效应,任何测试手段或多或少都会改变系统运行,这个对profiler同样适用!

       总之,提高运行效率的前提是你必须要知道CPU到底干了些什么干的怎么样。

    4.不要让自己大海捞针

       大海捞针只是对调试的一种生动比喻。

       经常听到组里有人对自己正在调试的代码说shit!可以理解,因为代码不是他写的,他有足够的理由去shit bug百出的代码,只要他自己不要写出这种代码,否则有一天同组的其它人可能同样会shit他写的代码。为何会有大海捞针呢?肯定是有人把针掉到海里咯;那针为何会掉在海里呢?肯定是有人不小心或草率呗。所以当你在抱怨针那么难找的时候,你是否想过是你自己草率地丢掉的。同样,当你调试个半死的时候,你是否想过你要好好反省一下当初为了寻求捷径可能没有严格地遵守好的编码设计规范、没有检测一些假设条件或算法的正确性、没有将一些可能存在问题的代码打上记号呢?关于如何写高质量请参考林锐的《高质量c++/c编程指南》或《关于C的0x8本“经书”》(http://blog.sina.com.cn/u/4a317b79010004mc)。

       如果你确实已经把针掉在海里是,为了防止在找到之前刺到自己,你必须要做一些防范工作,比如戴上安全手套。同样,为了尽能地暴露和捕捉问题根源,我们可以设计比较全面的错误跟踪代码。怎么来做呢?尽可能对每个函数调用失败作出处理,尽可能检测每个参数输入输出的有效性包括指针以及检测是否过多或过少地调用某个过程。错误跟踪能够让你知道你大概把针掉在哪个位置。

    5.重现并隔离问题

       如果你不是把针掉在大海了,而是掉在草堆里,那要好办写。因为至少我们可以把草堆分成很多块,一块一块的找。对于模块独立的大型项目,使用隔离方法往往是对付那些隐藏极深bug的最后方法。如果问题的出现是间歇性的,我们有必要设法去重现它并记录使其重现的整个过程以备在下一次可以利用这些条件去重现问题。如果你确信可以使用记录的那些条件去重现问题,那么我们就可以着手去隔离问题。怎么隔离呢?我们可以用#ifdef把一些可能和问题无关的代码关闭,把系统最小化到仍能够重现问题的地步。如果还是无法定位问题所在,那么有必要打开“工具箱”了。可以试着用ICE或数据监视器去查看某个可疑变量的变化;可以使用跟踪工具获得函数调用的情况包括参数的传递;检查内存是否崩溃以及堆栈溢出的问题。

    6.以退为进

       猎人为了不使自己在森林里迷路,他常常会在树木上流下一些标记,以备自己将来有一天迷路时可以根据这些标记找到出路。对过去代码的修改进行跟踪记录对将来出现问题之后的调试很有帮助。假如有一天,你最近一次修改的程序跑了很久之后忽然死掉了,那么你这时的第一反映就是我到底改动了些什么呢,因为上次修改之前是好的。那么如何检测这次相对于上次的修改呢?没错,代码控制系统SCS或称版本控制系统VCS(Concurrent Version Control,CVS是VCS的演化版本)。将上个版本check in下来后和当前测试版本比较。比较的工具可以是SCS/VCS/CVS自带的diff工具或其它功能更强的比较工具,比如BeyondCompare和ExamDiff。通过比较,记录所有改动的代码,分析所有可能导致问题的可疑代码。

    7.确定测试的完整性

       你怎么知道你的测试有多全面呢?覆盖测试(coverage testing)可以回答这个问题。覆盖测试工具可以告诉你CPU到底执行了那些代码。好的覆盖工具通常可以告诉你大概20%到40%代码没有问题,而其余的可能存在bug。覆盖工具有不同的测试级别,用户可以根据自己的需要选择某个级别。即使你很确信你的单元测试已经很全面并且没有dead code,覆盖工具还是可以为你指出一些潜在的问题,看下面的代码:

    if (i >= 0 && (almostAlwaysZero == 0 || (last = i)))

    如果almostAlwaysZero为非0,那么last=i赋值语句就被跳过,这可能不是你所期望的。这种问题通过覆盖工具的条件测试功能可以轻松的被发现。

       总之,覆盖测试对于提高代码质量很有帮助。

    8.提高代码质量意味着节省时间

       有研究表明软件开发的时间超过80%被用在下面几个方面:

    .调试自己的代码(单元测试)

    .调试自己和其他相关的代码(模块间测试)

    .调试整个系统(系统测试)

    更糟糕的是你可能需要花费10-200倍的时间来找一个bug,而这个bug在开始的时候可能很容易就能找到。一个小bug可能让你付出巨大的代价,即使这个bug对整个系统的性能没有太大的影响,但很可能会影响让那些你可以看得到的部分。所以我们必须要养成良好的编码和测试手段以求更高的代码质量,以便缩短调试的代码。

    9.发现它,分析它,解决它

       这世界没有万能的膏药。profile再强大也有力不从心的时候;内存监视器再好,也有无法发现的时候;覆盖工具再好用,也有不能覆盖的地方。一些隐藏很深的问题即使用尽所有工具也有可能无法查到其根源,这时我们能做的就是通过这些问题所表现出来的外在现象或一些数据输出来发现其中的规律或异常。一旦发现任何异常,一定要深入地理解并回溯其根源,直到解决为止。

    10.利用初学者的思维

       有人这样说过:“有些事情在初学者的脑子里可能有各种各样的情况,可在专家的头脑里可能就很单一”。有时候,有些简单的问题会被想的很复杂,有些简单的系统别设计的很复杂,就是由于你的“专家思维”。当你被问题难住时,关掉电脑,出去走走,把你的问题和你的朋友甚至你的小狗说说,或许他们可以给你意想不到的启发。

      总结:嵌入式调试也是一门艺术。就想其它的艺术一样,如果你想取得成功,你必须具备智慧、经验并懂得使用工具。只要我们能够很好地领悟Oracle这十条秘诀,我相信我们在嵌入式测试方面就能够取得成功。
     

  • 软件测试之7×24性能测试注意事项

    2009-04-30 08:59:32

    软件测试之7×24性能测试注意事项

    一、检查并记录运行环境情况
     1、当前运行的程序(不必要的都关闭)
     2、当前内存使用情况
     3、当前磁盘使用情况
     4、web服务器日志记录设置,没有必要的话关闭日志记录或清空日志
     5、测试开始前web服务启动后不要进行访问,让服务器空转5分钟以上,并监控内存、CPU的使用状况
     6、服务器启动后进行一小段时间的访问,让服务端完成初始化工作(热身)
     7、以上工作完成、各项指标正常后再进行测试
     8、最好挂一牌子写上“正在测试,勿动,请与×××联系”
     9、如果可能测试网络环境与工作环境隔离开
     10、检查网络带宽是否足够
     11、系统中当前运行进程是否正常
     13、检查是否有计划任务,如果不需要就关闭
     14、关闭所有无关的系统服务和进程

    二、用例及测试数据准备
     1、准备大量的测试数据(数据量太小的话会导致长时间运行后系统使用缓存而不进行运算)
     2、每个测试用例返回的记录数不要过大或过小,要控制返回记录数过多或为空的用例的个数
     3、用例数据会直接影响相应时间,所以应选择典型的用例数据

    三、测试工具及客户端设置
     1、加大采样时间间隔
     2、不记录日志
     3、不保存临时数据
     4、保证工具有足够的临时空间
     5、设置屏幕保护
     6、执行期间锁定客户端,并最好挂一牌子写上“正在测试,勿动,请与×××联系”
     7、客户端带宽是否有限制,计算单个请求的平均流量大小并估计需要的带宽
     8、关闭所有计划任务,例如杀毒软件自动更新、自动杀毒等
     9、客户端系统分区及存放结果的分区最好为NTFS格式,否则可能由于分区格式限制导致测试停止

  • 测试人员的误区:迷信自动化

    2009-03-05 11:26:21

     终于有时间总结一下过去几年在微软的测试经验,谈谈对测试自动化的看法。
      先说说为什么做测试的人喜欢搞自动化。
      第一,自尊心。计算机科班出身的人都喜欢作开发(Dev)。做测试工作经常是身不由己,可是测试工作很多时间不需要编程,于是做测试的人想方设法写些程序,以显示自己也会编程。结果往往是欲罢不能,测试自动化程序越写越多,越写越复杂。后面我会谈谈测试自动化框架复杂的代价。
      第二,为了出成绩。很多测试组为了向管理层展示成绩,往往要拿出例如测试自动化达到80%,程序覆盖率达到90%。要我说,这些都是Bull Shit。就象小平同志说的“实践是检验真理的唯一标准”,我认为在测试中“用户不出问题是检验质量的唯一标准”。自动化做的再多,用户出了问题,也是白搭。另外,一个人就可以做的测试,自动化往往需要两个,三个。倒是解决就业的好方法。
      我对测试自动化的认识也有一个变化的过程。刚刚入行时也是很相信自动化,想方设法写一些从头到尾自动化的框架,觉得自动测试很过瘾。到微软的Portal Media Center组后也是和另外两个人做了一个相当复杂的用户界面的自动测试。其实现在想想,用自动测试发现的问题基本上可以一个人用手工测试完成,最多写些简单的测试辅助工具就可以完成。有些人可能会说自动化可以为产品的下一个版本节省测试时间。其实Portal Media Center 下一个版本出来时,所有户界面完全变了,80%以上的自动测试程序都需要改动。做完第一个版本,我们三个人全都走掉了。后面来的人往往宁可自己再写一套,也懒得改以前人的程序。自动化的浪费就是这样造成的。想说服别人用你开发的自动测试框架是很难的,所有人都想另搞一套。
      下面分几点讲讲为什么要放弃对测试自动化的幻想,和怎样进行低成本的有效测试。如果你还不能同意我对测试自动化的看法,可以去微软员工的Blog看看为什么Windows测试组用的WTT测试框架被称作“Waste of Tester Time"。我最基本的观点不是说测试自动化不能测出bug,而是想问:一个比较复杂的测试自动化框架所造成的人力浪费,值不值得最终的结果?如果不做测试自动化,能不能达到同样的效果。以我的亲身经历,去年我的测试组两个人对应开发组五个人,项目经理三个人的工作量,去年做了好几个Release,Hotfix只有两三个。我们旁边的测试组七八个人对应五六个Dev。他们又是自动化,又是搞程序覆盖率,好不热闹,Hotfix 也不少。按一个人的人工成本12万美元,我们组省至少三个人的成本36万美元。
      第一,不要指望自动化能帮你找bug。软件bug和生物的bug很像,测试的规律是bug少的地方bug越少,bug多地方越找越多。做测试自动化,往往在开发自动化的时候,该发现的bug就发现了。自动化开发完成,再想发现更多bug就很难了。这是无论你怎样跑你的自动化,也不会发现新的bug。
      第二,不要指望自动化对Regression Test的测试的贡献。软件的特点是如果一次做对了,以后永远不会出错。当程序出现变动时,只要针对变动的部分测试就可以了,以前测过的东西,如果和变动没有关联就不会出错。相反如果,程序出现很大变化,自动化可能完全不能用了。
      第三,自动化不如测试工具加手工测试。我不建议测试人员作全面自动化,相反我建议测试人员多做小巧灵活的测试工具。自动化往往需要自动判Pass或Fail。 想想你如果测试用于生成
    http://www.microsoft.com/的页面的产品,你如何判断页面框架生成的正确?很多东西是动态产生的,你很难确认所有的内容的正确性。如果你自己用这个产品手工做个页面,用肉眼很容易判断所有相关和不相关的内容生成的正确性。我就是用这个方法在工作中发现了网页上谁也想不到的bug, 如果用自动化很难在测试阶段发现这个bug。
      第四,软件项目的生命周期就定了自动化的无用。现在很多网络应用项目的生命周期都很短,一个项目从生到死不过两三年。死的定义是项目进入Sustain Engineering维持状态。自动化原来的一个主要目的是使软件测试的未来阶段越来越容易,成本越来越低。可是当一个项目死掉了,自动化还有什么用。而且最新的敏捷开发,软件的要求,程序,接口,界面在不断变化,自动化怎么可能跟得上变化。与其去搞自动化,不如多理解变化,直接测试变化的东西。
    如何进行有效测试?
      第一,测试人员的自信心可以建立在读程序的能力上。在一个项目中,开发人员的工作是研究新技术,写出最好的程序。测试人员应该在开发人员研究的基础之上,更好的理解新技术,读懂程序。看懂程序可以使测试工作非常高效。不懂内部程序的人,可能会设计三十个test cases, 才能找到一个bug。 懂程序的人每个test case都可能发现一个或多个bug。 我有30%的bug都是读程序读出来的。由于对开发人员的程序有很深的理解,即使release后出了问题,也能很快理解问题出在什么地方,是否是bug。
      第二,测试人员写测试程序的时间应该尽量最小化。测试人员测试的时间分配应该是, 30%读程序,20%写测试程序,50%写Test Cases和运行Test Cases。好的测试员的工作重点应该放在理解要求,理解客户需要,思考在什么条件下程序会出错,而不是思考如何去自动化。如果时间都放在设计自动化上了,必然会影响测试,分散测试资源。测试人员应该边读程序边测试,读程序帮助找到好的Test Case,测试帮助验证理解和猜测。
      第三,测试人员要学会讨价还价。很多时候项目经理,开发人员搞得东西不是客户马上需要的,或许是永远用不到的。测试人员可以和项目经理研究先测什么,后测什么,那些不测。比如,我做的一个项目,我发现30%的功能是现在用处不大,所以我直接告诉项目经理那些东西我不会去测的。事实证明,这样做节省了很多人力。
      第四,测试人员要多花时间参与设计。测试人员一定要紧跟项目经理和开发人员的要求变化和设计。理解每一个要求的影响。在每个项目周期中,去比较当前版本和以前版本的所有程序变化。重点测试变化。
      总之,少做自动化,多写小工具,读懂程序,是高效省钱的测试方法,除非你钱多得没地方花。下次有谁建议搞什么测试自动化构架,告诉他“That is bullshit”。
  • 捕捉登出时间解决方案-----java中session的正确理解收藏

    2009-02-23 17:01:24

     捕捉登出时间解决方案-----java中session的正确理解收藏
            前段时间要做一个捕捉用户登入和登出时间的功能,查了很多资料,做了很多测试,总结出两套方案,其中对session有了进一步的认识。

     

            用户的登入时间很好做了,在用户验证成功通过后,得到当前系统时间记录就行;如果系统用的是Acegi的话,可以写一个类,继承Acegi中的AuthenticationProcessingFilter.java,并覆盖其onSuccessfulAuthentication方法,故名思意,这个方法就是acegi在对用户成功通过时进行的一个附加操作的方法,在这个方法里你可以记录当前用户id、时间、ip等等日志信息到数据库中。

     

            但要捕捉用户的登出时间确实是很麻烦,首先要知道是http是无状态连接协议,当用户不通过注销方法登出而直接关闭浏览器或者结束进程时,服务器根本无法捕捉这个事件,不管客户端发生了什么服务器也不知道,用户仅仅从服务器那得到了一个sessionid存储在浏览器进程的内存中或者cookie中,网上很多说用window.onunload( )等js方式来捕捉用户登出事件其实也其不通,因为用户可以直接杀死进程或者在新窗口页中打开链接,然后把原窗口关闭,这时通过js捕捉到关闭浏览器事件并发送请求告诉服务器,但其实用户还并没有离开系统,只不过换了个浏览器浏览页面。还有就是通过session过期来捕捉,但在系统正常运行下session死亡只有两种可能:

    1.session的持有者(即客户端浏览器)在最大无活动等待时间(MaxInactiveInterval)内无任何响应或请求  
    2.session被调用invalidate()方法强制弊而当用户关闭了浏览器后标志着session将不再发送请求到服务器,服务器也不会无缘无故调用它的invalidate()方法,这样session只能等到time-out时才会销毁,如果系统设置了session的MaxInactiveInterval为-1的话,那这个session将永远存活到服务器关闭为止。

    所以session不能反应出用户的活动状态,浏览器关闭事件也不能完全得出用户一定是退出了系统。

     

         那这个登出时间到底怎样才能得到呢?事实如此,只能降低期望了,和老大讨论了许久,最后只有两套方案行得通,如下。

     

     一,以性能换精度,也是我最终采用的方案,我们可以精确地得到用户登入时间,而登出时间我们得到个大概的时间就行,不需要太精确,毕竟系统不是什么很机密性的东西。采用session监听器来实现,写一类,继承HttpSessionListener,实现其public void sessionDestroyed(HttpSessionEvent arg0) 和public void sessionCreated(HttpSessionEvent arg0) 方法,当用户session失效时会走sessionDestroyed方法,在其里面得到的当前时间就是用户的大概登出时间,前提是系统session过期时间不能设置太长,要不误差就太大了,半小时就差不多。

     

    二,以精度换性能,b/s系统的页面一般都会带有头部、脚部页面或者是框架型的,这样我们就可以在公用的头脚或主框架页中插入一个隐藏的iframe或者代码块。里头写一段js方法,window.setInterval()之类的,每隔一小段时间(假设为2分钟)向服务器发送一个空请求,目的仅仅是让服务器知道客户端还开着我的页面,不管是以哪种方式。服务器接受这个请求后,新建一个Map对象(新建一javabean类也行,里面有用户id和请求时间两个属性),put两个元素,当前用户id为value,一约定代号为key,如“userid”,另一元素请求时间为value,同样一约定代号为key,如“requesttime”;然后再以这个对象为value,sessionid为key ,set一个attribute到session当中,当下次再收到一个请求时,再重复上部操作,这样请求时间会不断更新。做完这些之后,还需要添加一个定时调度的job,每隔一小段时间(假设为3分钟),遍历session对象,从其中的map或者javabean中取出userid 和 requesttime,判断这个请求时间和当前时间的时差是否大于三分钟,如果是则说明用户已经没有再向服务器发送请求,即没有页面再用户端打开着,用户离开了,记录最后一次请求时间,也就是用户的登出时间。

     

           目前还没有想到其它更好的方法,现在这种机制下好像也只能这样了,还有一点需要注意,如果采用在用户登录成功时记录登录时间的方式,在要求并发数较大的时候不可行,今天对我们项目组做的一个系统进行登录过程50、100用户并发测试时,失败率极高,而问题就出在登录时向数据库记录登入时间和更新最高访问人数时出现的sql事务死锁情况,所以后来更换了方案,在登录时将当前时间为value,sessionid为key,set到session当中,当这个session过期时,通过httpsessionlistener捕捉到该事件,从session中取出该用户的登录时间和当前时间一并存入数据库,后者作为登出时间;最高访问人数也放在了application里,这样性能上提高了不少。

     

            如果要得到用户的在线时间的话,需要注意的是,由于一个浏览器进程共用一个session,一个浏览器中的所有标签也是共用一个session,在用户登录成功时需要通过当前sessionid判断用户是否重复登录了,如果是则在此时就不应该将当前时间set到session中,而应该保持上次存储的登录时间。

     

     

    /*********** 下面再引入一下网上比较经典的描述,更有利于理解session和cookie ************/

    让我们用几个例子来描述一下cookie和session机制之间的区别与联系。笔者曾经常去的一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠,然而一次性消费5杯咖啡的机会微乎其微,这时就需要某种方式来纪录某位顾客的消费数量。想象一下其实也无外乎下面的几种方案:
    1、该店的店员很厉害,能记住每位顾客的消费数量,只要顾客一走进咖啡店,店员就知道该怎么对待了。这种做法就是协议本身支持状态。
    2、发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
    3、发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。由于HTTP协议是无状态的,而出于种种考虑也不希望使之成为有状态的,因此,后面两种方案就成为现实的选择。具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端

    保持状态的方案。同时我们也看到,由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择。


     

  • 转自微软内部资料:编写高性能 Web 应用程序的 10 个技巧

    2009-01-14 16:18:31

    编写高性能 Web 应用程序的 10 个技巧 转自微软资料
    数据层性能
    技巧 1 — 返回多个结果集
    技巧 2 — 分页的数据访问
    技巧 3 — 连接池
    技巧 4 — ASP.NET 缓存 API
    技巧 5 — 每请求缓存
    技巧 6 — 后台处理
    技巧 7 — 页输出缓存和代理服务器
    技巧 8 — 运行 IIS 6.0(只要用于内核缓存)
    技巧 9 — 使用 Gzip 压缩
    技巧 10 — 服务器控件视图状态
    小结
    ====================================================
    使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信。正因为如此简单,所以很多开发人员就不会花时间来设计其应用程序的结构,以获得更好的性能了。在本文中,我将讲述 10 个用于编写高性能 Web 应用程序的技巧。但是我并不会将这些建议仅局限于 ASP.NET 应用程序,因为这些应用程序只是 Web 应用程序的一部分。本文不作为对 Web 应用程序进行性能调整的权威性指南 — 一整本书恐怕都无法轻松讲清楚这个问题。请将本文视作一个很好的起点。

    成为工作狂之前,我原来喜欢攀岩。在进行任何大型攀岩活动之前,我都会首先仔细查看指南中的路线,阅读以前游客提出的建议。但是,无论指南怎么好,您都需要真正的攀岩体验,然后才能尝试一个特别具有挑战性的攀登。与之相似,当您面临修复性能问题或者运行一个高吞吐量站点的问题时,您只能学习如何编写高性能 Web 应用程序。

    我的个人体验来自在 Microsoft 的 ASP.NET 部门作为基础架构程序经理的经验,在此期间我运行和管理 www.ASP.NET,帮助设计社区服务器的结构,社区服务器是几个著名 ASP.NET 应用程序(组合到一个平台的 ASP.NET Forums、.Text 和 nGallery)。我确信有些曾经帮助过我的技巧对您肯定也会有所帮助。

    您应该考虑将应用程序分为几个逻辑层。您可能听说过 3 层(或者 n 层)物理体系结构一词。这些通常都是规定好的体系结构方式,将功能在进程和/或硬件之间进行了物理分离。当系统需要扩大时,可以很轻松地添加更多的硬件。但是会出现一个与进程和机器跳跃相关的性能下降,因此应该避免。所以,如果可能的话,请尽量在同一个应用程序中一起运行 ASP.NET 页及其相关组件。

    因为代码分离以及层之间的边界,所以使用 Web 服务或远程处理将会使得性能下降 20% 甚至更多。

    数据层有点与众不同,因为通常情况下,最好具有专用于数据库的硬件。然而进程跳跃到数据库的成本依然很高,因此数据层的性能是您在优化代码时首先要考虑的问题。

    在深入应用程序的性能修复问题之前,请首先确保对应用程序进行剖析,以便找出具体的问题所在。主要性能计数器(如表示执行垃圾回收所需时间百分比的计数器)对于找出应用程序在哪些位置花费了其主要时间也非常有用。然而花费时间的位置通常非常不直观。

    本文讲述了两种类型的性能改善:大型优化(如使用 ASP.NET 缓存),和进行自身重复的小型优化。这些小型优化有时特别有意思。您对代码进行一点小小的更改,就会获得很多很多时间。使用大型优化,您可能会看到整体性能的较大飞跃。而使用小型优化时,对于某个特定请求可能只会节省几毫秒的时间,但是每天所有请求加起来,则可能会产生巨大的改善。

    数据层性能


    谈到应用程序的性能调整,有一个试纸性的测试可用来对工作进行优先级划分:代码是否访问数据库?如果是,频率是怎样的?请注意,这一相同测试也可应用于使用 Web 服务或远程处理的代码,但是本文对这些内容未做讲述。

    如果某个特定的代码路径中必需进行数据库请求,并且您认为要首先优化其他领域(如字符串操作),则请停止,然后执行这个试纸性测试。如果您的性能问题不是非常严重的话,最好花一些时间来优化一下与数据库、返回的数据量、进出数据库的往返频率相关的花费时间。

    了解这些常规信息之后,我们来看一下可能会有助于提高应用程序性能的十个技巧。首先,我要讲述可能会引起最大改观的更改。

    ===============================
    技巧 1 — 返回多个结果集


    仔细查看您的数据库代码,看是否存在多次进入数据库的请求路径。每个这样的往返都会降低应用程序可以提供的每秒请求数量。通过在一个数据库请求中返回多个结果集,可以节省与数据库进行通信所需的总时间长度。同时因为减少了数据库服务器管理请求的工作,还会使得系统伸缩性更强。

    虽然可以使用动态 SQL 返回多个结果集,但是我首选使用存储过程。关于业务逻辑是否应该驻留于存储过程的问题还存在一些争议,但是我认为,如果存储过程中的逻辑可以约束返回数据的话(缩小数据集的大小、缩短网络上所花费时间,不必筛选逻辑层的数据),则应赞成这样做。

    使用 SqlCommand 实例及其 ExecuteReader 方法填充强类型的业务类时,可以通过调用 NextResult 将结果集指针向前移动。图 1 显示了使用类型类填充几个 ArrayList 的示例会话。只从数据库返回您需要的数据将进一步减少服务器上的内存分配。

    ==================================
    技巧 2 — 分页的数据访问


    ASP.NET DataGrid 具有一个很好的功能:数据分页支持。在 DataGrid 中启用分页时,一次会显示固定数量的记录。另外,在 DataGrid 的底部还会显示分页 UI,以便在记录之间进行导航。该分页 UI 使您能够在所显示的数据之间向前和向后导航,并且一次显示固定数量的记录。

    还有一个小小的波折。使用 DataGrid 的分页需要所有数据均与网格进行绑定。例如,您的数据层需要返回所有数据,那么 DataGrid 就会基于当前页筛选显示的所有记录。如果通过 DataGrid 进行分页时返回了 100,000 个记录,那么针对每个请求会放弃 99,975 个记录(假设每页大小为 25 个记录)。当记录的数量不断增加时,应用程序的性能就会受到影响,因为针对每个请求必须发送越来越多的数据。

    要编写性能更好的分页代码,一个极佳的方式是使用存储过程。图 2 显示了针对 Northwind 数据库中的 Orders 表进行分页的一个示例存储过程。简而言之,您此时要做的只是传递页索引和页大小。然后就会计算合适的结果集,并将其返回。

    在社区服务器中,我们编写了一个分页服务器控件,以完成所有的数据分页。您将会看到,我使用的就是技巧 1 中讨论的理念,从一个存储过程返回两个结果集:记录的总数和请求的数据。

    返回记录的总数可能会根据所执行查询的不同而有所变化。例如,WHERE 子句可用来约束返回的数据。为了计算在分页 UI 中显示的总页数,必须了解要返回记录的总数。例如,如果总共有 1,000,000 条记录,并且要使用一个 WHERE 子句将其筛选为 1000 条记录,那么分页逻辑就需要了解记录的总数才能正确呈现分页 UI。

    ==============================
    技巧 3 — 连接池


    在 Web 应用程序和 SQL Server™ 之间设置 TCP 连接可能是一个非常消耗资源的操作。Microsoft 的开发人员到目前为止能够使用连接池已经有一段时间了,这使得他们能够重用数据库连接。他们不是针对每个请求都设置一个新的 TCP 连接,而是只在连接池中没有任何连接时才设置新连接。当连接关闭时,它会返回连接池,在其中它会保持与数据库的连接,而不是完全破坏该 TCP 连接。

    当然,您需要小心是否会出现泄漏连接。当您完成使用连接时,请一定要关闭这些连接。再重复一遍:无论任何人对 Microsoft?.NET Framework 中的垃圾回收有什么评论,请一定要在完成使用连接时针对该连接显式调用 Close 或 Dispose。不要相信公共语言运行库 (CLR) 会在预先确定的时间为您清除和关闭连接。尽管 CLR 最终会破坏该类,并强制连接关闭,但是当针对对象的垃圾回收真正发生时,并不能保证。

    要以最优化的方式使用连接池,需要遵守一些规则。首先打开连接,执行操作,然后关闭该连接。如果您必须如此的话,可以针对每个请求多次打开和关闭连接(最好应用技巧 1),但是不要一直将连接保持打开状态并使用各种不同的方法对其进行进出传递。第二,使用相同的连接字符串(如果使用集成身份验证的话,还要使用相同的线程标识)。如果不使用相同的连接字符串,例如根据登录的用户自定义连接字符串,那么您将无法得到连接池提供的同一个优化值。如果您使用集成身份验证,同时还要模拟大量用户,连接池的效率也会大大下降。尝试跟踪与连接池相关的任何性能问题时,.NET CLR 数据性能计数器可能非常有用。

    每当应用程序连接资源时,如在另一个进程中运行的数据库,您都应该重点考虑连接该资源所花时间、发送或检索数据所花时间,以及往返的数量,从而进行优化。优化应用程序中任何种类的进程跳跃都是获得更佳性能的首要一点。

    应用层包含了连接数据层、将数据转换为有意义类实例和业务流程的逻辑。例如社区服务器,您要在其中填充Forums 或 Threads集合,应用业务规则(如权限);最重要的是要在其中执行缓存逻辑。

    ================================
    技巧 4 — ASP.NET 缓存 API


    编写应用程序代码行之前,一个首要完成的操作是设计应用层的结构,以便最大化利用 ASP.NET 缓存功能。

    如果您的组件要在 ASP.NET 应用程序中运行,则只需在该应用程序项目中包括一个 System.Web.dll 引用。当您需要访问该缓存时,请使用 HttpRuntime.Cache 属性(通过 Page.Cache 和 HttpContext.Cache 也可访问这个对象)。

    对于缓存数据,有几个规则。首先,如果数据可能会多次使用时,则这是使用缓存的一个很好的备选情况。第二,如果数据是通用的,而不特定于某个具体的请求或用户时,则也是使用缓存的一个很好的备选情况。如果数据是特定于用户或请求的,但是寿命较长的话,仍然可以对其进行缓存,但是这种情况可能并不经常使用。第三,一个经常被忽略的规则是,有时可能您缓存得太多。通常在一个 x86 计算机上,为了减少内存不足错误出现的机会,您会想使用不高于 800MB 的专用字节运行进程。因此缓存应该有个限度。换句话说,您可能能够重用某个计算结果,但是如果该计算采用 10 个参数的话,您可能要尝试缓存 10 个排列,这样有可能给您带来麻烦。一个要求 ASP.NET 的最常见支持是由于过度缓存引起的内存不足错误,尤其是对于大型数据集。


    图 3 ASP.NET缓存

    缓存有几个极佳的功能,您需要对它们有所了解。首先,缓存会实现最近最少使用的算法,使得 ASP.NET 能够在内存运行效率较低的情况下强制缓存清除 - 从缓存自动删除未使用过的项目。第二,缓存支持可以强制失效的过期依赖项。这些依赖项包括时间、密钥和文件。时间经常会用到,但是对于 ASP.NET 2.0,引入了一个功能更强的新失效类型:数据库缓存失效。它指的是当数据库中的数据发生变化时自动删除缓存中的项。有关数据库缓存失效的详细信息,请参阅 MSDN?Magazine 2004 年 7 月的 Dino Esposito Cutting Edge 专栏。要了解缓存的体系结构,请参阅图 3。

    =======================
    技巧 5 — 每请求缓存


    在本文前面部分,我提到了经常遍历代码路径的一些小改善可能会导致较大的整体性能收益。对于这些小改善,其中有一个绝对是我的最爱,我将其称之为“每请求缓存”。

    缓存 API 的设计目的是为了将数据缓存较长的一段时间,或者缓存至满足某些条件时,但每请求缓存则意味着只将数据缓存为该请求的持续时间。对于每个请求,要经常访问某个特定的代码路径,但是数据却只需提取、应用、修改或更新一次。这听起来有些理论化,那么我们来举一个具体的示例。

    在社区服务器的论坛应用程序中,页面上使用的每个服务器控件都需要个性化的数据来确定使用什么外观、使用什么样式表,以及其他个性化数据。这些数据中有些可以长期缓存,但是有些数据却只针对每个请求提取一次,然后在执行该请求期间对其重用多次,如要用于控件的外观。

    为了达到每请求缓存,请使用 ASP.NET HttpContext。对于每个请求,都会创建一个 HttpContext 实例,在该请求期间从 HttpContext.Current 属性的任何位置都可访问该实例。该 HttpContext 类具有一个特殊的 Items 集合属性;添加到此 Items 集合的对象和数据只在该请求持续期间内进行缓存。正如您可以使用缓存来存储经常访问的数据一样,您也可以使用 HttpContext.Items 来存储只基于每个请求使用的数据。它背后的逻辑非常简单:数据在它不存在的时候添加到 HttpContext.Items 集合,在后来的查找中,只是返回 HttpContext.Items 中的数据。

    =====================
    技巧 6 — 后台处理


    通往代码的路径应该尽可能快速,是吗?可能有时您会觉得针对每个请求执行的或者每 n 个请求执行一次的任务所需资源非常多。发送电子邮件或者分析和验证传入数据就是这样的一些例子。

    剖析 ASP.NET Forums 1.0 并重新构建组成社区服务器的内容时,我们发现添加新张贴的代码路径非常慢。每次添加新张贴时,应用程序首先需要确保没有重复的张贴,然后必须使用“坏词”筛选器分析该张贴,分析张贴的字符图释,对张贴添加标记并进行索引,请求时将张贴添加到合适的队列,验证附件,最终张贴之后,立即向所有订阅者发出电子邮件通知。很清楚,这涉及很多操作。

    经研究发现,大多数时间都花在了索引逻辑和发送电子邮件上。对张贴进行索引是一个非常耗时的操作,人们发现内置的 System.Web.Mail 功能要连接 SMYP 服务器,然后连续发送电子邮件。当某个特定张贴或主题领域的订阅者数量增加时,执行 AddPost 功能所需的时间也越来越长。

    并不需要针对每个请求都进行电子邮件索引。理想情况下,我们想要将此操作进行批处理,一次索引 25 个张贴或者每五分钟发送一次所有电子邮件。我们决定使用以前用于对数据缓存失效进行原型设计的代码,这个失效是用于最终进入 Visual Studio® 2005 的内容的。

    System.Threading 命名空间中的 Timer 类非常有用,但是在 .NET Framework 中不是很有名,至少对于 Web 开发人员来说是这样。创建之后,这个 Timer 类将以一个可配置的间隔针对 ThreadPool 中的某个线程调用指定的回调。这就表示,您可以对代码进行设置,使其能够在没有对 ASP.NET 应用程序进行传入请求的情况下得以执行,这是后台处理的理想情况。您还可以在此后台进程中执行如索引或发送电子邮件之类的操作。

    但是,这一技术有几个问题。如果应用程序域卸载,该计时器实例将停止触发其事件。另外,因为 CLR 对于每个进程的线程数量具有一个硬性标准,所以可能会出现这样的情形:服务器负载很重,其中计时器可能没有可在其基础上得以完成的线程,在某种程度上可能会造成延迟。ASP.NET 通过在进程中保留一定数量的可用线程,并且仅使用总线程的一部分用于请求处理,试图将上述情况发生的机会降到最低。但是,如果您具有很多异步操作时,这可能就是一个问题了。

    这里没有足够的空间来放置该代码,但是您可以下载一个可以看懂的示例,网址是 www.rob-howard.net。请了解一下 Blackbelt TechEd 2004 演示中的幻灯片和演示。

    =========================

    技巧 7 — 页输出缓存和代理服务器


    ASP.NET 是您的表示层(或者说应该是您的表示层);它由页、用户控件、服务器控件(HttpHandlers 和 HttpModules)以及它们生成的内容组成。如果您具有一个 ASP.NET 页,它会生成输出(HTML、XML、图像或任何其他数据),并且您针对每个请求运行此代码时,它都会生成相同的输出,那么您就拥有一个可用于页输出缓存的绝佳备选内容。

    将此行内容添加页的最上端

    <%@ Page OutputCache VaryByParams="none" Duration="60" %>

    就可以高效地为此页生成一次输出,然后对它进行多次重用,时间最长为 60 秒,此时该页将重新执行,输出也将再一次添加到 ASP.NET 缓存。通过使用一些低级程序化 API 也可以完成此行为。对于输出缓存有几个可配置的设置,如刚刚讲到的 VaryByParams 属性。VaryByParams 刚好被请求到,但还允许您指定 HTTP GET 或 HTTP POST 参数来更改缓存项。例如,只需设置 VaryByParam="Report" 即可对 default.aspx?Report=1 或 default.aspx?Report=2 进行输出缓存。通过指定一个以分号分隔的列表,还可以指定其他参数。

    很多人都不知道何时使用输出缓存,ASP.NET 页还会生成一些位于缓存服务器下游的 HTTP 标头,如 Microsoft Internet Security and Acceleration Server 或 Akamai 使用的标头。设置了 HTTP 缓存标头之后,可以在这些网络资源上对文档进行缓存,客户端请求也可在不必返回原始服务器的情况下得以满足。

    因此,使用页输出缓存不会使得您的应用程序效率更高,但是它可能会减少服务器上的负载,因为下游缓存技术会缓存文档。当然,这可能只是匿名内容;一旦它成为下游之后,您就再也不会看到这些请求,并且再也无法执行身份验证以阻止对它的访问了。

    ========================
    技巧 8 — 运行 IIS 6.0(只要用于内核缓存)


    如果您未运行 IIS 6.0 (Windows Server? 2003),那么您就错过了 Microsoft Web 服务器中的一些很好的性能增强。在技巧 7 中,我讨论了输出缓存。在 IIS 5.0 中,请求是通过 IIS 然后进入 ASP.NET 的。涉及到缓存时,ASP.NET 中的 HttpModule 会接收该请求,并返回缓存中的内容。

    如果您正在使用 IIS 6.0,就会发现一个很好的小功能,称为内核缓存,它不需要对 ASP.NET 进行任何代码更改。当请求由 ASP.NET 进行输出缓存时,IIS 内核缓存会接收缓存数据的一个副本。当请求来自网络驱动程序时,内核级别的驱动程序(无上下文切换到用户模式)就会接收该请求,如果经过了缓存,则会将缓存的数据刷新到响应,然后完成执行。这就表示,当您将内核模式缓存与 IIS 和 ASP.NET 输出缓存一起使用时,就会看到令人不敢相信的性能结果。在 ASP.NET 的 Visual Studio 2005 开发过程中,我一度是负责 ASP.NET 性能的程序经理。开发人员完成具体工作,但是我要看到每天进行的所有报告。内核模式缓存结果总是最有意思的。最常见的特征是网络充满了请求/响应,而 IIS 运行时的 CPU 使用率只有大约 5%。这太令人震惊了!当然使用 IIS 6.0 还有一些其他原因,但是内核模式缓存是其中最明显的一个。

    ===========================
    技巧 9 — 使用 Gzip 压缩


    虽然使用 gzip 并不一定是服务器性能技巧(因为您可能会看到 CPU 使用率的提高),但是使用 gzip 压缩可以减少服务器发送的字节数量。这就使人们觉得页速度加快了,并且还减少了带宽的用量。根据所发送数据、可以压缩的程度以及客户端浏览器是否支持(IIS 只会向支持 gzip 压缩的客户端发送经过 gzip 压缩的内容,如 Internet Explorer 6.0 和 Firefox),您的服务器每秒可以服务于更多的请求。实际上,几乎每当您减少所返回数据的数量时,都会增加每秒请求数。

    Gzip 压缩已经内置到 IIS 6.0 中,并且其性能比 IIS 5.0 中使用的 gzip 压缩要好的多,这是好消息。但不幸的是,当尝试在 IIS 6.0 中打开 gzip 压缩时,您可能无法在 IIS 的属性对话中找到该设置。IIS 小组在该服务器中置入了卓越的 gzip 功能,但是忘了包括一个用于启用该功能的管理 UI。要启用 gzip 压缩,您必须深入到 IIS 6.0 的 XML 配置设置内部(这样不会引起心脏虚弱)。顺便提一句,这归功于 OrcsWeb 的 Scott Forsyth,他帮助我提出了在 OrcsWeb 上宿主的 www.asp.net 服务器的这个问题。

    本文就不讲述步骤了,请阅读 Brad Wilson 的文章,网址是 IIS6 Compression。还有一篇有关为 ASPX 启用压缩的知识库文章,网址是 Enable ASPX Compression in IIS。但是您应该注意,由于一些实施细节,IIS 6.0 中不能同时存在动态压缩和内核缓存。

    ==============================
    技巧 10 — 服务器控件视图状态


    视图状态是一个有趣的名称,用于表示在所生成页的隐藏输出字段中存储一些状态数据的 ASP.NET。当该页张贴回服务器时,服务器可以分析、验证、并将此视图状态数据应用回该页的控件树。视图状态是一个非常强大的功能,因为它允许状态与客户端一起保持,并且它不需要 cookie 或服务器内存即可保存此状态。很多 ASP.NET 服务器控件都使用视图状态来保持在与页元素进行交互期间创建的设置,例如保存对数据进行分页时显示的当前页。

    然而使用视图状态也有一些缺点。首先,服务或请求页时,它都会增加页的总负载。对张贴回服务器的视图状态数据进行序列化或取消序列化时,也会发生额外的开销。最后,视图状态会增加服务器上的内存分配。

    几个服务器控件有着过度使用视图状态的趋势,即使在并不需要的情况下也要使用它,其中最著名的是 DataGrid。ViewState 属性的默认行为是启用,但是如果您不需要,则可以在控件或页级别关闭。在控件内,只需将 EnableViewState 属性设置为 false,或者在页中使用下列设置即可对其进行全局设置:

    <%@ Page EnableViewState="false" %>

    如果您不回发页,或者总是针对每个请求重新生成页上的控件,则应该在页级别禁用视图状态。

    ==============================
    小结


    我为您讲述了一些我认为在编写高性能 ASP.NET 应用程序时有所帮助的技巧。正如我在本文前面部分提到的那样,这是一个初步指南,并不是 ASP.NET 性能的最后结果。(有关改善 ASP.NET 应用程序性能的信息,请参阅 Improving ASP.NET Performance。)只有通过自己的亲身体验才能找出解决具体性能问题的最好方法。但是,在您的旅程中,这些技巧应该会为您提供一些好的指南

  • 配置Jprofile及注册码分享(网络收集)

    2008-12-16 17:15:47

    配置Jprofile

    配置本地监控步骤
    第一步,在安装被监控程序的机器上安装windows版的jprofiler5.

    第二步,New Session,选择New server Integration。

     


    选择服务类型,本次配置使用的是TOMCAT5.5,可以选择Apache Tomcat 5.x

    第三步,选择本地机器。

    第四步,选择本地机器选择服务启动文件,如:D:\dhcc\soft\DhccOA\bin\appserver\apache-tomcat-5.5.20\bin\startup.bat,点击NEXT

     第五步,选择JVM类型及版本

    第六步,设置端口号,使用默认的端口号。

    第七步,使用默认选择,不立即连接。

    第八步,显示配置信息。

    第七步,完成配置,并启动。OK


    配置远程监控步骤:
    第一步,在监控端安装windows版的jprofiler5,由于服务也是windows操作系统,在服务器端安装windows版的jprofiler5。

    第二步,在监控端配置,点击NEW SESSION,选择New Remote Integration,如下图:


    选择On a remote computer,选择Platform. if the remote computer(一般为被监控机器的类型),点击NEXT。


    第三步,输入被监控机器的IP,如下图,点击NEXT。


    第四步,输入被监控机器中,jprofiler的安装位置(如:D:\Program Files\jprofiler5),点击NEXT。


    第五步,选择JVM的类型和版本,其他默认,点击NEXT。


    第六步,JProfiler监听的端口,使用默认值即可,点击NEXT。


    第七步,选择启动模式,选择第一个,点击NEXT。


    第八步,显示待修改的信息,将此信息copy出来,待配置被监控的机器时用。


    第九步,完成配置,选择第二项,不立即连接。


    第十步,在被监控的服务器端,修改服务启动文件,如果服务为TOMCAT,将startup.bat文件中的JAVA_OPTS的后面添加第八步中copy出来的内容:

    -agentlib:jprofilerti=port=8849 "-Xbootclasspath/a:D:\Program Files\jprofiler5\bin\agent.jar"

    保存此文件。

    第十一步,在环境变量PATH中添加第八步中copy出来的内容:

    D:\Program Files\jprofiler5\bin\windows(注意前面加分号)。

    第十二步,在被监控端,启动startup.bat,提示等待连接的信息,在监控端,选择要连接的SESSION,点击START,在下一出现的页面,点击OK,连接成功,被监控端的服务启动,待启动完成后,监控端能显示对方服务的内存、CPU等占用情况。


    监控资源的配置
    另外特别注意的是,在SESSION配置页面,要添加被监控的资源或CLASS这样才有实际意义,


     

    常出现的问题
    1.        JVM出了bug报告,开始不知道怎么回事,耽误了很多时间,其实就是参数冲突)。还有一个个性配置信息就是要有一个叫LD_LIBRARY_PATH的环境变量,那我就修改了catalina.sh,在里面加入export LD_LIBRARY_PATH=D:\Program Files\jprofiler5\bin\windows。 (转)

    2.        有时也要将Jprofiler安装目录下bin下的jprofiler.vmoptions文件中的虚拟内存适量的改小。

     

    JProfiler连接Weblogic (转)
    http://www.ej-technologies.com/
       1.本地连接

      1.1环境说明

      本地安装JProfiler,Weblogic相关工具,相关破解可以在网上找到.

      1.2步骤说明

      1.打开工具JProfiler后,在Session菜单下选择New windows,弹出Quickstart窗口界面,在该界面选择第三项An application server, locally or remotely,然后点击Next.

      2.进入Integration wizard界面,选择应用服务的类型和版本.此处,我们选择BEA Weblogic 8.1,然后点击Next.

      3.选择连接的类型,是本地还是远程,这里我们选择本地(on this computer),然后点击Next.

      4.选择Weblogic的启动文件Startweblogic.cmd,然后点击Next.

      5.选择JDK的提供厂商和其版本.这里我们选择了Sun Microsystems的1.4版,然后点击Next.

      6.选择两种处理模式,这里选择第一种,符合应用服务(JIT/hotspot complation enabled)

      7.选择JProfiler的使用端口,对于本地连接来说,此处作用不大,用默认即可

      8.选择第一个,启动weblogic时,试图去连接本次建立的连接,一直会等待到成功连接,而选择第二个,若是发现weblogic没有启动,将不做等待这里我们选择第一项.

      9.对前面设置的内容统一展现,若是检查没有问题,则点击Next,进行下一步操作.

      10.点击Finish,完成了本次连接的配置,若是选择了马上连接,则下一步开始连接.

      11.这里对配置好的连接进行设置,根据需要可以进行过虑等设置,完成后点击OK.

      12.开始连接本地的weblogic应用,连接成功后,可以得到相关的信息

    附:
    JProfiler.v4.2.2+注册机

    JProfiler是一个全功能的Java剖析工具(profiler),专用於分析J2SE和J2EE应用程式。它把CPU、线程和记忆体的剖析组合在一个强大的应用中。JProfiler可提供许多IDE整合和应用服务器整合功能。JProfiler直觉式的GUI让你可以找到性能瓶颈、抓住内存泄漏(memory leaks)、并解决多线程的问题。它让你得以对heap walker作资源回收器的root analysis,可以轻易找出内存泄漏;heap快照(snapshot)模式让未被引用(reference)的对象, 稍微被引用的对象、或在终结(finalization)序列的对象都会被移除;整合精灵以便剖析瀏览器的Java外掛功能。

    下载地址:
    http://download.ej-technologies.com/jprofiler/jprofiler_windows_4_2_2.exe
    解密过程:
    将EJ[1].Technologies.JProfiler.v4.2.2.Incl.Keymaker-AGAiN压缩包中的jkgone.jar解压到
    根目录或其它目录下运行如下命令.
    java -jar jkgone.jar

    附其它版本的注册码
    http://download.ej-technologies.com/jprofiler/jprofiler_windows_3_3_1.exe
    JProfiler 4.0
    Name and Company: anything s/n: A-G666#76114F-1olm9mv1i5uuly#0126

    JProfiler 3.3.1
    s/n: A-XiV7#20128F-1nf9r2z1qepp2e#7120

    EJ Technologies JProfiler 2.2.1
    S/N: A-DWP#OWNZ#YOU-212hyr

    JProfiler 3.3
    S/N: A-XiV6#62267F-1tfbcghardqqd#16312<br>

    JProfiler 3.2.0
    S/N: A-GAiN#91584F-vd0mmz13mkf00#181013<br>or<br>A-GAiN#22031F-1giul8u16x7p65#121218<br>or<br>A-GAiN#98900F-1j62dw18rpusn#111117<br>

    JProfiler 3.2
    S/N: A-GAiN#70503F-l7qte9gtq77c#81111<br>or<br>A-GAiN#19132F-y2fnayai9yu8#141420<br>


    目前最新版为4.3,大家可以申请试用10天,如果大家还需要其它版本的注册码回复

    Jprofiler 5.1.2

    下载地址:http://www.ej-technologies.com/download/jprofiler/files.php

    官方试用版下载:
    http://www.ej-technologies.com/download/jprofiler/trial.php .
     

  • 常用的性能测试方法和测试要点

    2008-12-16 13:58:04

    常用的性能测试方法和测试要点

      1、明确用户的性能需求(显示的和隐式的),性能测试点,找出瓶颈

      1)用户直接需求的和使用过程中(行业经验)可能遇到的性能瓶颈点必须测试和分析到。当然,客户不需要的,也没有必要去花时间和精力。

      2)从中获取相应的性能测试参数,峰值和平均值。

      3)客户的性能容忍度和系统所能承受的容忍度同样重要。

      4)确认系统运行的最低硬件环境要求(虽然硬件便宜的多了,但客户能不能改造自己的环境还得客户说了算)

      5)如果可以的话,将系统的容错性做为性能测试的一部分进行测试

      2、测试对象和性能负载分布

      1)基本的3个对对像:C/S、B/S中的客户端和服务器,其中还有网络进行连接或中间件。

      2)服务端可能分为数据端、业务端和服务容器。

      3)跟据实际的测试结果合理的进行相应的性能负载分布。

      3、负载、容量和压力测试逐一进行(如果需要)

      1)更多的情况下,性能测试中出现的问题是最初的设计时应存在的问题。如果可能,建议对相应的性能提前做测试和优化。

      2)够用就好,不是所有的系统都要进行性能测试,一切以客户需求和实际需要为准。

      4、测试点

      1)CPU和内存使用(系统自身的原因)。是否可以正常的使用和释放,是否存在内存溢出。

      2)访问的速度(客户需求或是实际的应用要求说了算)

      3)网络。网络传输速度,网络传输丢包率。(找些工具,有免费的)

      4)服务器。指令、服务应答响应时间,服务器对信息处理的时效性,服务器对峰值的处理(建议进行服务器优化或是进行服务负载均衡,有大量的文档对此进行描述)

      5)中间件。中间件在信息传递中的处理性能及信息处理的正确性。

      5、测试和监控数据

      1)均值下的持续运行(通过分析对整体的性能进行预测和评估)

      2)短时间的峰值运行(分析系统的处理能力)

      3)最低配置和最佳配置下的性能对比

      4)多用户。同时访问,同时提交。

      5)对 4 中的数据进行记录和监控

      6、选择测试工具

      现有的测试工具太多了,不在一一列举。

      适用就好,推荐开源的工具。

     

  • 软件测试计划(转贴)

    2008-12-06 14:10:07

    测试计划

    1引言
    1.1编写目的
    本测试计划的具体编写目的,指出预期的读者范围。

    1.2背景
    说明:

    a.  测试计划所从属的软件系统的名称;

    b.  该开发项目的历史,列出用户和执行此项目测试的计算中心,说明在开始执行本测试计划之前必须完成的各项工作。

    1.3定义
    列出本文件中用到的专门术语的定义和外文首字母组词的原词组。

    1.4参考资料
    列出要用到的参考资料,如:

    a.  本项目的经核准的计划任务书或合同、上级机关的批文;

    b.  属于本项目的其他已发表的文件;

    c.  本文件中各处引用的文件、资料,包括所要用到的软件开发标准。列出这些文件的标题、文件编号、发表日期和出版单位,说明能够得到这些文件资料的来源。

    2计划
    2.1软件说明
    提供一份图表,并逐项说明被测软件的功能、输入和输出等质量指标,作为叙述测试计划的提纲。

    2.2测试内容
    列出组装测试和确认测试中的每一项测试内容的名称标识符、这些测试的进度安排以及这些测试的内容和目的,例如模块功能测试、接口正确性测试、数据文卷存取的测试、运行时间的测试、设计约束和极限的测试等。

    2.3测试1(标识符)
    给出这项测试内容的参与单位及被测试的部位。

    2.3.1进度安排
    给出对这项测试的进度安排,包括进行测试的日期和工作内容(如熟悉环境。培训、准备输入数据等)。

    2.3.2条件
    陈述本项测试工作对资源的要求,包括:

    a.  设备所用到的设备类型、数量和预定使用时间;

    b.  软件列出将被用来支持本项测试过程而本身又并不是被测软件的组成部分的软件,如测试驱动程序、测试监控程序、仿真程序、桩模块等等;

    c.  人员列出在测试工作期间预期可由用户和开发任务组提供的工作人员的人数。技术水平及有关的预备知识,包括一些特殊要求,如倒班操作和数据键入人员。

    2.3.3测试资料
    列出本项测试所需的资料,如:

    a.  有关本项任务的文件;

    b.  被测试程序及其所在的媒体;

    c.  测试的输入和输出举例;

    d.  有关控制此项测试的方法、过程的图表。

    2.3.4测试培训
    说明或引用资料说明为被测软件的使用提供培训的计划。规定培训的内容、受训的人员及从事培训的工作人员。

    2.4测试2(标识符)
    用与本测试计划2.3条相类似的方式说明用于另一项及其后各项测试内容的测试工作计划。

    3测试设计说明
    3.1测试1(标识符)
    说明对第一项测试内容的测试设计考虑。

    3.1.1控制
    说明本测试的控制方式,如输入是人工、半自动或自动引入、控制操作的顺序以及结果的记录方法。

    3.1.2输入
    说明本项测试中所使用的输入数据及选择这些输入数据的策略。

    3.1.3输出
    说明预期的输出数据,如测试结果及可能产生的中间结果或运行信息。

    3.1.4过程
    说明完成此项测试的一个个步骤和控制命令,包括测试的准备、初始化、中间步聚和运行结束方式。

    3.2测试2(标识符)
    用与本测试计划3.l条相类似的方式说明第2项及其后各项测试工作的设计考虑。

    4评价准则
    4.1范围
    说明所选择的测试用例能够接查的范围及其局限性。

    4.2数据整理
    陈述为了把测试数据加工成便于评价的适当形式,使得测试结果可以同,已知结果进行比较而要用到的转换处理技术,如手工方式或自动方式;如果是用自动方式整理数据,还要说明为进行处理而要用到的硬件、软件资源。

    4.3尺度
    说明用来判断测试工作是否能通过的评价尺度,如合理的输出结果的类型、测试输出结果与预期输出之间的容许偏离范围、允许中断或停机的最大次数。

     

  • 从编码方面提高网站性能的手段

    2008-11-27 16:27:57

    从编码方面提高网站性能的手段

    一、缓存

    缓存是ASP.NET中提高性能的重要手段,缓存一般遵循以下原则:

    1)  在页面中将静态内容与动态内容分割开来

    考虑将动态内容作成用户控件

    2)  缓存合理的数据

    一般应当缓存应用程序集的数据、多个用户共同使用的数据、静态数据、生成数据需要很大开销的动态数据、DataSet以及自定义对象等。不要缓存数据库连接对象、DataReader。

    3)  选择适当的方式

    如可以使用页面缓存指令,API等。

    二、视图状态

    视图状态放在页面中名为_VIEWSTATE的表单隐藏域里面,随页面一起被发送到客户端,在用户提交页面时,又被提交到服务器。

    1)  如果不需要视图状态,则禁用

    视图状态默认是允许的,如果页面不进行PostBack,如果不处理服务器控件的事件,如果服务器控件的数据每次都需要重新计算等

    2)  尽量减少视图状态中存放的对象

    三、         关于页面处理(减少页面生成的时间和过程)

    1)              应尽量减少页面文件的大小

    2)              通过检测Page.IsPostBack减少代码执行的数量

    3)              禁止使用Debug=“true”,减少页面生成过程中生成额外的调试信息

    4)              使用Server.Transfer而不使用Response.Redirect,减少服务器和客户端间的往返

    5)              尽量使用客户端验证,减少服务器和客户端间的往返

    6)              在适当的场合使用服务器控件

    7)              尽量避免嵌套的服务器控件

    四、         避免使用Page.DataBind和DataBinder.Eval

    五、         关于Application对象和Session对象

    1)  使用静态属性存储数据而不使用Application对象,在Application对象里存储只读类型的数据都将回提高性能

    2)  尽量使用InProc模式的Session,这个模式是最快的

    3)  在Session里存储基本类型的数据减少序列化的所消耗的资源

    4)  如果不用Session变量,使用EnvableViewState=“false”禁用

    5)  如果不修改Session变量的值,尽量使用ReadOnly属性设置

    六、         关于字符串操作

    1)  尽量使用Response.Write将结果输出到浏览器,这种方法是最快的。不要将字符串连接在一起一次输出。

    2)  在字符串短并且少的情况下可以使用String.Concat方法,而在字符串长度未知,并且字符串大的情况下,使用StringBuilder对象

    3)  不要使用strVar==“”来判断字符串是否为“”,这样它会创建额外的字符串,请使用strVar==String.Empty代替或者使用strVar.Length==0来判断

    4)  请使用String.Compare方法进行字符串的比较

    七、         关于数据访问

    1)  尽量使用存储过程返回数据,不要直接在代码中进行查询

    2)  在数据库中只返回有用的数据结果,不要选择不使用的数据字段

    3)  进行使用DataReader进行数据绑定,DataReader是单向只读的

    4)  尽量一次返回多个数据集而不是每个记录集分别打开一次数据库连接进行查询

    5)  尽量晚的打开数据库,尽量早的关闭数据库

    6)  使用连接池提高性能

    7)  使用ExecuteNonQuery方法执行不返回数据的操作,使用ExecuteScalar方法返回单个结果的操作,使用Commandbehavīor.Sequentialaccess返回二进制数据或者大数据

    8)  如果多次相同的查询,请使用Command.Prepare方法

    9)  使用GetOrdinal方法预先得到索引值,使用索引值比使用字符串的列名查询数据效率更高

    八、         关于代码优化

    1)  在解析基本数据类型时,使用Try方法如果解析失败,会抛出异常,使用TryParse方法则只执行Else下的语句。

    2)  使用AppendAllText、WriteAllBytes等方法读写文件内容可以优化性能

    3)  将循环判定条件放在for语句外

    4)  避免在循环里创建对象

    5)  尽量减少装箱的次数

    6)  不要使用例外控制程序的流程

    7)  在循环中不要使用不变的对象属性或者字段

    8)  使用for循环代替foreach循环遍历结合内容

    9)  数组是所有集合中最快的,如果没有特殊需要,尽量使用数组代替集合

    10)    了解各个集合类型的特性,选择合适的类型

    11)    使用泛型避免减少装箱、拆箱

     

  • 怎样解决Java内存泄漏

    2008-11-14 14:09:12


    解决Java内存泄漏

    Java内存泄漏是每个Java程序员都会遇到的问题,程序在本地运行一切正常,可是布署到远端就会出现内存无限制的增长,最后系统瘫痪,那么如何最快最好的检测程序的稳定性,防止系统崩盘,作者用自已的亲身经历与各位分享解决这些问题的办法.
     
    作为Internet最流行的编程语言之一,Java现正非常流行.我们的网络应用程序就主要采用Java语言开发,大体上分为客户端、服务器和数据库三个层次.在进入测试过程中,我们发现有一个程序模块系统内存和CPU资源消耗急剧增加,持续增长到出现java.lang.OutOfMemoryError为止.经过分析Java内存泄漏是破坏系统的主要因素.这里与大家分享我们在开发过程中遇到的Java内存泄漏的检测和处理解决过程.

    一. Java是如何管理内存

    为了判断Java中是否有内存泄露,我们首先必须了解Java是如何管理内存的.Java的内存管理就是对象的分配和释放问题.在Java中,内存的分配是由程序完成的,而内存的释放是由垃圾收集器(Garbage Collection,GC)完成的,程序员不需要通过调用函数来释放内存,但它只能回收无用并且不再被其它对象引用的那些对象所占用的空间.

    Java的内存垃圾回收机制是从程序的主要运行对象开始检查引用链,当遍历一遍后发现没有被引用的孤立对象就作为垃圾回收.GC为了能够正确释放对象,必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控.监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就是该对象不再被引用.

    在Java中,这些无用的对象都由GC负责回收,因此程序员不需要考虑这部分的内存泄露.虽然,我们有几个函数可以访问GC,例如运行GC的函数System.gc(),但是根据Java语言规范定义,该函数不保证JVM的垃圾收集器一定会执行.因为不同的JVM实现者可能使用不同的算法管理GC.通常GC的线程的优先级别较低.JVM调用GC的策略也有很多种,有的是内存使用到达一定程度时,GC才开始工作,也有定时执行的,有的是平缓执行GC,有的是中断式执行GC.但通常来说,我们不需要关心这些.

    二. 什么是Java中的内存泄露

    导致内存泄漏主要的原因是,先前申请了内存空间而忘记了释放.如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器GC验证这些对象是否不再需要.如果存在对象的引用,这个对象就被定义为"有效的活动",同时不会被释放.要确定对象所占内存将被回收,我们就要务必确认该对象不再会被使用.典型的做法就是把对象数据成员设为null或者从集合中移除该对象.但当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理.

    在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是有被引用的,即在有向树形图中,存在树枝通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象.如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存.

    这里引用一个常看到的例子,在下面的代码中,循环申请Object对象,并将所申请的对象放入一个Vector中,如果仅仅释放对象本身,但因为Vector仍然引用该对象,所以这个对象对GC来说是不可回收的.因此,如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null.实际上这些对象已经是无用的,但还被引用,GC就无能为力了(事实上GC认为它还有用),这一点是导致内存泄漏最重要的原因. 再引用另一个例子来说明Java的内存泄漏.假设有一个日志类Logger,其提供一个静态的log(String msg),任何其它类都可以调用Logger.Log(message)来将message的内容记录到系统的日志文件中.

    Logger类有一个类型为HashMap的静态变量temp,每次在执行log(message)的时候,都首先将message的值写入temp中(以当前线程+当前时间为键),在退出之前再从temp中将以当前线程和当前时间为键的条目删除.注意,这里当前时间是不断变化的,所以log在退出之前执行删除条目的操作并不能删除执行之初写入的条目.这样,任何一个作为参数传给log的字符串最终由于被Logger的静态变量temp引用,而无法得到回收,这种对象保持就是我们所说的Java内存泄漏. 总的来说,内存管理中的内存泄漏产生的主要原因:保留下来却永远不再使用的对象引用.

    三. 几种典型的内存泄漏

    我们知道了在Java中确实会存在内存泄漏,那么就让我们看一看几种典型的泄漏,并找出他们发生的原因和解决方法.

    3.1 全局集合

    在大型应用程序中存在各种各样的全局数据仓库是很普遍的,比如一个JNDI-tree或者一个session table.在这些情况下,必须注意管理储存库的大小.必须有某种机制从储存库中移除不再需要的数据.

    通常有很多不同的解决形式,其中最常用的是一种周期运行的清除作业.这个作业会验证仓库中的数据然后清除一切不需要的数据.另一种管理储存库的方法是使用反向链接(referrer)计数.然后集合负责统计集合中每个入口的反向链接的数目.这要求反向链接告诉集合何时会退出入口.当反向链接数目为零时,该元素就可以从集合中移除了.

    3.2 缓存
    缓存一种用来快速查找已经执行过的操作结果的数据结构.因此,如果一个操作执行需要比较多的资源并会多次被使用,通常做法是把常用的输入数据的操作结果进行缓存,以便在下次调用该操作时使用缓存的数据.缓存通常都是以动态方式实现的,如果缓存设置不正确而大量使用缓存的话则会出现内存溢出的后果,因此需要将所使用的内存容量与检索数据的速度加以平衡.

    常用的解决途径是使用java.lang.ref.SoftReference类坚持将对象放入缓存.这个方法可以保证当虚拟机用完内存或者需要更多堆的时候,可以释放这些对象的引用.

    3.3 类装载器
    Java类装载器的使用为内存泄漏提供了许多可乘之机.一般来说类装载器都具有复杂结构,因为类装载器不仅仅是只与"常规"对象引用有关,同时也和对象内部的引用有关.比如数据变量,方法和各种类.这意味着只要存在对数据变量,方法,各种类和对象的类装载器,那么类装载器将驻留在JVM中.既然类装载器可以同很多的类关联,同时也可以和静态数据变量关联,那么相当多的内存就可能发生泄漏.

    四. 如何检测和处理内存泄漏

    如何查找引起内存泄漏的原因一般有两个步骤:第一是安排有经验的编程人员对代码进行走查和分析,找出内存泄漏发生的位置;第二是使用专门的内存泄漏测试工具进行测试.

    第一个步骤:在代码走查的工作中,可以安排对系统业务和开发语言工具比较熟悉的开发人员对应用的代码进行了交叉走查,尽量找出代码中存在的数据库连接声明和结果集未关闭、代码冗余等故障代码.

    第二个步骤:就是检测Java的内存泄漏.在这里我们通常使用一些工具来检查Java程序的内存泄漏问题.市场上已有几种专业检查Java内存泄漏的工具,它们的基本工作原理大同小异,都是通过监测Java程序运行时,所有对象的申请、释放等动作,将内存管理的所有信息进行统计、分析、可视化.开发人员将根据这些信息判断程序是否有内存泄漏问题.这些工具包括Optimizeit Profiler,JProbe Profiler,JinSight , Rational 公司的Purify等.

    4.1检测内存泄漏的存在
    这里我们将简单介绍我们在使用Optimizeit检查的过程.通常在知道发生内存泄漏之后,第一步是要弄清楚泄漏了什么数据和哪个类的对象引起了泄漏.

    一般说来,一个正常的系统在其运行稳定后其内存的占用量是基本稳定的,不应该是无限制的增长的.同样,对任何一个类的对象的使用个数也有一个相对稳定的上限,不应该是持续增长的.根据这样的基本假设,我们持续地观察系统运行时使用的内存的大小和各实例的个数,如果内存的大小持续地增长,则说明系统存在内存泄漏,如果特定类的实例对象个数随时间而增长(就是所谓的“增长率”),则说明这个类的实例可能存在泄漏情况.

    另一方面通常发生内存泄漏的第一个迹象是:在应用程序中出现了OutOfMemoryError.在这种情况下,需要使用一些开销较低的工具来监控和查找内存泄漏.虽然OutOfMemoryError也有可能应用程序确实正在使用这么多的内存;对于这种情况则可以增加JVM可用的堆的数量,或者对应用程序进行某种更改,使它使用较少的内存.

    但是,在许多情况下,OutOfMemoryError都是内存泄漏的信号.一种查明方法是不间断地监控GC的活动,确定内存使用量是否随着时间增加.如果确实如此,就可能发生了内存泄漏.

    4.2处理内存泄漏的方法
    一旦知道确实发生了内存泄漏,就需要更专业的工具来查明为什么会发生泄漏.JVM自己是不会告诉您的.这些专业工具从JVM获得内存系统信息的方法基本上有两种:JVMTI和字节码技术(byte code instrumentation).Java虚拟机工具接口(Java Virtual Machine Tools Interface,JVMTI)及其前身Java虚拟机监视程序接口(Java Virtual Machine Profiling Interface,JVMPI)是外部工具与JVM通信并从JVM收集信息的标准化接口.字节码技术是指使用探测器处理字节码以获得工具所需的信息的技术.

    Optimizeit是Borland公司的产品,主要用于协助对软件系统进行代码优化和故障诊断,其中的Optimizeit Profiler主要用于内存泄漏的分析.Profiler的堆视图就是用来观察系统运行使用的内存大小和各个类的实例分配的个数的.

    首先,Profiler会进行趋势分析,找出是哪个类的对象在泄漏.系统运行长时间后可以得到四个内存快照.对这四个内存快照进行综合分析,如果每一次快照的内存使用都比上一次有增长,可以认定系统存在内存泄漏,找出在四个快照中实例个数都保持增长的类,这些类可以初步被认定为存在泄漏.通过数据收集和初步分析,可以得出初步结论:系统是否存在内存泄漏和哪些对象存在泄漏(被泄漏).

    接下来,看看有哪些其他的类与泄漏的类的对象相关联.前面已经谈到Java中的内存泄漏就是无用的对象保持,简单地说就是因为编码的错误导致了一条本来不应该存在的引用链的存在(从而导致了被引用的对象无法释放),因此内存泄漏分析的任务就是找出这条多余的引用链,并找到其形成的原因.查看对象分配到哪里是很有用的.同时只知道它们如何与其他对象相关联(即哪些对象引用了它们)是不够的,关于它们在何处创建的信息也很有用.
      
    最后,进一步研究单个对象,看看它们是如何互相关联的.借助于Profiler工具,应用程序中的代码可以在分配时进行动态添加,以创建堆栈跟踪.也有可以对系统中所有对象分配进行动态的堆栈跟踪.这些堆栈跟踪可以在工具中进行累积和分析.对每个被泄漏的实例对象,必然存在一条从某个牵引对象出发到达该对象的引用链.处于堆栈空间的牵引对象在被从栈中弹出后就失去其牵引的能力,变为非牵引对象.因此,在长时间的运行后,被泄露的对象基本上都是被作为类的静态变量的牵引对象牵引.

    总而言之, Java虽然有自动回收管理内存的功能,但内存泄漏也是不容忽视,它往往是破坏系统稳定性的重要因素.

     

  • java性能优化

    2008-11-14 14:06:14

    一、避免在循环条件中使用复杂表达式


    在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。

    例子:
    import java.util.Vector;
    class CEL {
        void method (Vector vector) {
            for (int i = 0; i < vector.size (); i++)  // Violation
                ; // ...
        }
    }

    更正:
    class CEL_fixed {
        void method (Vector vector) {
            int size = vector.size ()
            for (int i = 0; i < size; i++)
                ; // ...
        }
    }

    二、为'Vectors' 和 'Hashtables'定义初始大小


    JVM为Vector扩充大小的时候需要重新创建一个更大的数组,将原原先数组中的内容复制过来,最后,原先的数组再被回收。可见Vector容量的扩大是一个颇费时间的事。
    通常,默认的10个元素大小是不够的。你最好能准确的估计你所需要的最佳大小。

    例子:
    import java.util.Vector;
    public class DIC {
        public void addObjects (Object[] o) {
            // if length > 10, Vector needs to expand
            for (int i = 0; i< o.length;i++) {    
                v.add(o);   // capacity before it can add more elements.
            }
        }
        public Vector v = new Vector();  // no initialCapacity.
    }

    更正:
    自己设定初始大小。
        public Vector v = new Vector(20);  
        public Hashtable hash = new Hashtable(10);

    参考资料:
    Dov Bulka, "Java Performance and Scalability Volume 1: Server-Side Programming
    Techniques" Addison Wesley, ISBN: 0-201-70429-3 pp.55 – 57

    三、在finally块中关闭Stream


    程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。
             
    例子:
    import java.io.*;
    public class CS {
        public static void main (String args[]) {
            CS cs = new CS ();
            cs.method ();
        }
        public void method () {
            try {
                FileInputStream fis = new FileInputStream ("CS.java");
                int count = 0;
                while (fis.read () != -1)
                    count++;
                System.out.println (count);
                fis.close ();
            } catch (FileNotFoundException e1) {
            } catch (IOException e2) {
            }
        }
    }
             
    更正:
    在最后一个catch后添加一个finally块

    参考资料:
    Peter Haggar: "Practical Java - Programming Language Guide".
    Addison Wesley, 2000, pp.77-79

    四、使用'System.arraycopy ()'代替通过来循环复制数组


    'System.arraycopy ()' 要比通过循环来复制数组快的多。
             
    例子:
    public class IRB
    {
        void method () {
            int[] array1 = new int [100];
            for (int i = 0; i < array1.length; i++) {
                array1 [i] = i;
            }
            int[] array2 = new int [100];
            for (int i = 0; i < array2.length; i++) {
                array2 [i] = array1 [i];                 // Violation
            }
        }
    }
             
    更正:
    public class IRB
    {
        void method () {
            int[] array1 = new int [100];
            for (int i = 0; i < array1.length; i++) {
                array1 [i] = i;
            }
            int[] array2 = new int [100];
            System.arraycopy(array1, 0, array2, 0, 100);
        }
    }
             
    参考资料:
    http://www.cs.cmu.edu/~jch/java/speed.html

    五、让访问实例内变量的getter/setter方法变成”final”


    简单的getter/setter方法应该被置成final,这会告诉编译器,这个方法不会被重载,所以,可以变成”inlined”

    例子:
    class MAF {
        public void setSize (int size) {
             _size = size;
        }
        private int _size;
    }

    更正:
    class DAF_fixed {
        final public void setSize (int size) {
             _size = size;
        }
        private int _size;
    }

    参考资料:
    Warren N. and Bishop P. (1999), "Java in Practice", p. 4-5
    Addison-Wesley, ISBN 0-201-36065-9

    六、避免不需要的instanceof操作


    如果左边的对象的静态类型等于右边的,instanceof表达式返回永远为true。
             
    例子:         
    public class UISO {
        public UISO () {}
    }
    class Dog extends UISO {
        void method (Dog dog, UISO u) {
            Dog d = dog;
            if (d instanceof UISO) // always true.
                System.out.println("Dog is a UISO");
            UISO uiso = u;
            if (uiso instanceof Object) // always true.
                System.out.println("uiso is an Object");
        }
    }
             
    更正:         
    删掉不需要的instanceof操作。
             
    class Dog extends UISO {
        void method () {
            Dog d;
            System.out.println ("Dog is an UISO");
            System.out.println ("UISO is an UISO");
        }
    }

    七、避免不需要的造型操作


    所有的类都是直接或者间接继承自Object。同样,所有的子类也都隐含的“等于”其父类。那么,由子类造型至父类的操作就是不必要的了。
    例子:
    class UNC {
        String _id = "UNC";
    }
    class Dog extends UNC {
        void method () {
            Dog dog = new Dog ();
            UNC animal = (UNC)dog;  // not necessary.
            Object o = (Object)dog;         // not necessary.
        }
    }
             
    更正:         
    class Dog extends UNC {
        void method () {
            Dog dog = new Dog();
            UNC animal = dog;
            Object o = dog;
        }
    }
             
    参考资料:
    Nigel Warren, Philip Bishop: "Java in Practice - Design Styles and Idioms
    for Effective Java".  Addison-Wesley, 1999. pp.22-23

    八、如果只是查找单个字符的话,用charAt()代替startsWith()


    用一个字符作为参数调用startsWith()也会工作的很好,但从性能角度上来看,调用用String API无疑是错误的!
             
    例子:
    public class PCTS {
        private void method(String s) {
            if (s.startsWith("a")) { // violation
                // ...
            }
        }
    }
             
    更正         
    将'startsWith()' 替换成'charAt()'.
    public class PCTS {
        private void method(String s) {
            if ('a' == s.charAt(0)) {
                // ...
            }
        }
    }
             
    参考资料:
    Dov Bulka, "Java Performance and Scalability Volume 1: Server-Side Programming
    Techniques"  Addison Wesley, ISBN: 0-201-70429-3

    九、使用移位操作来代替'a / b'操作


    "/"是一个很“昂贵”的操作,使用移位操作将会更快更有效。

    例子:
    public class SDIV {
        public static final int NUM = 16;
        public void calculate(int a) {
            int div = a / 4;            // should be replaced with "a >> 2".
            int div2 = a / 8;         // should be replaced with "a >> 3".
            int temp = a / 3;
        }
    }

    更正:
    public class SDIV {
        public static final int NUM = 16;
        public void calculate(int a) {
            int div = a >> 2;  
            int div2 = a >> 3;
            int temp = a / 3;       // 不能转换成位移操作
        }
    }

    十、使用移位操作代替'a * b'


    同上。
    [i]但我个人认为,除非是在一个非常大的循环内,性能非常重要,而且你很清楚你自己在做什么,方可使用这种方法。否则提高性能所带来的程序晚读性的降低将是不合算的。

    例子:
    public class SMUL {
        public void calculate(int a) {
            int mul = a * 4;            // should be replaced with "a << 2".
            int mul2 = 8 * a;         // should be replaced with "a << 3".
            int temp = a * 3;
        }
    }

    更正:
    package OPT;
    public class SMUL {
        public void calculate(int a) {
            int mul = a << 2;  
            int mul2 = a << 3;
            int temp = a * 3;       // 不能转换
        }
    }

    十一、在字符串相加的时候,使用 ' ' 代替 " ",如果该字符串只有一个字符的话



    例子:
    public class STR {
        public void method(String s) {
            String string = s + "d"  // violation.
            string = "abc" + "d"      // violation.
        }
    }

    更正:
    将一个字符的字符串替换成' '
    public class STR {
        public void method(String s) {
            String string = s + 'd'
            string = "abc" + 'd'   
        }
    }

    十二、不要在循环中调用synchronized(同步)方法


    方法的同步需要消耗相当大的资料,在一个循环中调用它绝对不是一个好主意。

    例子:
    import java.util.Vector;
    public class SYN {
        public synchronized void method (Object o) {
        }
        private void test () {
            for (int i = 0; i < vector.size(); i++) {
                method (vector.elementAt(i));    // violation
            }
        }
        private Vector vector = new Vector (5, 5);
    }

    更正:
    不要在循环体中调用同步方法,如果必须同步的话,推荐以下方式:
    import java.util.Vector;
    public class SYN {
        public void method (Object o) {
        }
    private void test () {
        synchronized{//在一个同步块中执行非同步方法
                for (int i = 0; i < vector.size(); i++) {
                    method (vector.elementAt(i));   
                }
            }
        }
        private Vector vector = new Vector (5, 5);
    }

    十三、将try/catch块移出循环


    把try/catch块放入循环体内,会极大的影响性能,如果编译JIT被关闭或者你所使用的是一个不带JIT的JVM,性能会将下降21%之多!
             
    例子:         
    import java.io.FileInputStream;
    public class TRY {
        void method (FileInputStream fis) {
            for (int i = 0; i < size; i++) {
                try {                                      // violation
                    _sum += fis.read();
                } catch (Exception e) {}
            }
        }
        private int _sum;
    }
             
    更正:         
    将try/catch块移出循环         
        void method (FileInputStream fis) {
            try {
                for (int i = 0; i < size; i++) {
                    _sum += fis.read();
                }
            } catch (Exception e) {}
        }
             
    参考资料:
    Peter Haggar: "Practical Java - Programming Language Guide".
    Addison Wesley, 2000, pp.81 – 83

    十四、对于boolean值,避免不必要的等式判断


    将一个boolean值与一个true比较是一个恒等操作(直接返回该boolean变量的值). 移走对于boolean的不必要操作至少会带来2个好处:
    1)代码执行的更快 (生成的字节码少了5个字节);
    2)代码也会更加干净 。

    例子:
    public class UEQ
    {
        boolean method (String string) {
            return string.endsWith ("a") == true;   // Violation
        }
    }

    更正:
    class UEQ_fixed
    {
        boolean method (String string) {
            return string.endsWith ("a");
        }
    }

    十五、对于常量字符串,用'String' 代替 'StringBuffer'


    常量字符串并不需要动态改变长度。
    例子:
    public class USC {
        String method () {
            StringBuffer s = new StringBuffer ("Hello");
            String t = s + "World!";
            return t;
        }
    }

    更正:
    把StringBuffer换成String,如果确定这个String不会再变的话,这将会减少运行开销提高性能。

    十六、用'StringTokenizer' 代替 'indexOf()' 和'substring()'


    字符串的分析在很多应用中都是常见的。使用indexOf()和substring()来分析字符串容易导致StringIndexOutOfBoundsException。而使用StringTokenizer类来分析字符串则会容易一些,效率也会高一些。

    例子:
    public class UST {
        void parseString(String string) {
            int index = 0;
            while ((index = string.indexOf(".", index)) != -1) {
                System.out.println (string.substring(index, string.length()));
            }
        }
    }

    参考资料:
    Graig Larman, Rhett Guthrie: "Java 2 Performance and Idiom Guide"
    Prentice Hall PTR, ISBN: 0-13-014260-3 pp. 282 – 283

    十七、使用条件操作符替代"if (cond) return; else return;" 结构


    条件操作符更加的简捷
    例子:
    public class IF {
        public int method(boolean isDone) {
            if (isDone) {
                return 0;
            } else {
                return 10;
            }
        }
    }

    更正:
    public class IF {
        public int method(boolean isDone) {
            return (isDone ? 0 : 10);
        }
    }

    十八、使用条件操作符代替"if (cond) a = b; else a = c;" 结构


    例子:
    public class IFAS {
        void method(boolean isTrue) {
            if (isTrue) {
                _value = 0;
            } else {
                _value = 1;
            }
        }
        private int _value = 0;
    }

    更正:
    public class IFAS {
        void method(boolean isTrue) {
            _value = (isTrue ? 0 : 1);       // compact expression.
        }
        private int _value = 0;
    }

    十九、不要在循环体中实例化变量


    在循环体中实例化临时变量将会增加内存消耗

    例子:         
    import java.util.Vector;
    public class LOOP {
        void method (Vector v) {
            for (int i=0;i < v.size();i++) {
                Object o = new Object();
                o = v.elementAt(i);
            }
        }
    }
             
    更正:         
    在循环体外定义变量,并反复使用         
    import java.util.Vector;
    public class LOOP {
        void method (Vector v) {
            Object o;
            for (int i=0;i<v.size();i++) {
                o = v.elementAt(i);
            }
        }
    }

    二十、确定 StringBuffer的容量


    StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建 StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。

    例子:         
    public class RSBC {
        void method () {
            StringBuffer buffer = new StringBuffer(); // violation
            buffer.append ("hello");
        }
    }
             
    更正:         
    为StringBuffer提供寝大小。         
    public class RSBC {
        void method () {
            StringBuffer buffer = new StringBuffer(MAX);
            buffer.append ("hello");
        }
        private final int MAX = 100;
    }
             
    参考资料:
    Dov Bulka, "Java Performance and Scalability Volume 1: Server-Side Programming
    Techniques" Addison Wesley, ISBN: 0-201-70429-3 p.30 – 31

    二十一、尽可能的使用栈变量


    如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static? local?还是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。
             
    例子:
    public class USV {
        void getSum (int[] values) {
            for (int i=0; i < value.length; i++) {
                _sum += value[i];           // violation.
            }
        }
        void getSum2 (int[] values) {
            for (int i=0; i < value.length; i++) {
                _staticSum += value[i];
            }
        }
        private int _sum;
        private static int _staticSum;
    }     
             
    更正:         
    如果可能,请使用局部变量作为你经常访问的变量。
    你可以按下面的方法来修改getSum()方法:         
    void getSum (int[] values) {
        int sum = _sum;  // temporary local variable.
        for (int i=0; i < value.length; i++) {
            sum += value[i];
        }
        _sum = sum;
    }
             
    参考资料:         
    Peter Haggar: "Practical Java - Programming Language Guide".
    Addison Wesley, 2000, pp.122 – 125

    二十二、不要总是使用取反操作符(!)


    取反操作符(!)降低程序的可读性,所以不要总是使用。

    例子:
    public class DUN {
        boolean method (boolean a, boolean b) {
            if (!a)
                return !a;
            else
                return !b;
        }
    }

    更正:
    如果可能不要使用取反操作符(!)

    二十三、与一个接口 进行instanceof操作


    基于接口的设计通常是件好事,因为它允许有不同的实现,而又保持灵活。只要可能,对一个对象进行instanceof操作,以判断它是否某一接口要比是否某一个类要快。

    例子:
    public class INSOF {
        private void method (Object o) {
            if (o instanceof InterfaceBase) { }  // better
            if (o instanceof ClassBase) { }   // worse.
        }
    }

    class ClassBase {}
    interface InterfaceBase {}
  • 性能测试(并发负载压力)测试分析

    2008-10-28 10:05:08

    性能测试(并发负载压力)测试分析

    分析原则:
        • 具体问题具体分析(这是由于不同的应用系统,不同的测试目的,不同的性能关注点)
        • 查找瓶颈时按以下顺序,由易到难。
        服务器硬件瓶颈-〉网络瓶颈(对局域网,可以不考虑)-〉服务器操作系统瓶颈(参数配置)-〉中间件瓶颈(参数配置,数据库,web服务器等)-〉应用瓶颈(SQL语句、数据库设计、业务逻辑、算法等)
        注:以上过程并不是每个分析中都需要的,要根据测试目的和要求来确定分析的深度。对一些要求低的,我们分析到应用系统在将来大的负载压力(并发用户数、数据量)下,系统的硬件瓶颈在哪儿就够了。
        • 分段排除法 很有效

    分析的信息来源:
        •1 根据场景运行过程中的错误提示信息
        •2 根据测试结果收集到的监控指标数据

    一.错误提示分析
    分析实例:
    1 •Error: Failed to connect to server "10.10.10.30:8080": [10060] Connection
      •Error: timed out Error: Server "10.10.10.30" has shut down the connection prematurely

      分析:
    •A、应用服务死掉。
       (小用户时:程序上的问题。程序上处理数据库的问题)
    •B、应用服务没有死
       (应用服务参数设置问题)
        例:在许多客户端连接Weblogic应用服务器被拒绝,而在服务器端没有错误显示,则有可能是Weblogic中的server元素的AcceptBacklog属性值设得过低。如果连接时收到connection refused消息,说明应提高该值,每次增加25%
    •C、数据库的连接
       (1、在应用服务的性能参数可能太小了 2、数据库启动的最大连接数(跟硬件的内存有关))

    2  Error: Page download timeout (120 seconds) has expired

    分析:可能是以下原因造成
    •A、应用服务参数设置太大导致服务器的瓶颈
    •B、页面中图片太多
    •C、在程序处理表的时候检查字段太大多

    二.监控指标数据分析
    1.最大并发用户数:
    应用系统在当前环境(硬件环境、网络环境、软件环境(参数配置))下能承受的最大并发用户数。
    在方案运行中,如果出现了大于3个用户的业务操作失败,或出现了服务器shutdown的情况,则说明在当前环境下,系统承受不了当前并发用户的负载压力,那么最大并发用户数就是前一个没有出现这种现象的并发用户数。
    如果测得的最大并发用户数到达了性能要求,且各服务器资源情况良好,业务操作响应时间也达到了用户要求,那么OK。否则,再根据各服务器的资源情况和业务操作响应时间进一步分析原因所在。

    2.业务操作响应时间:
    • 分析方案运行情况应从平均事务响应时间图和事务性能摘要图开始。使用“事务性能摘要”图,可以确定在方案执行期间响应时间过长的事务。
    • 细分事务并分析每个页面组件的性能。查看过长的事务响应时间是由哪些页面组件引起的?问题是否与网络或服务器有关?
    • 如果服务器耗时过长,请使用相应的服务器图确定有问题的服务器度量并查明服务器性能下降的原因。如果网络耗时过长,请使用“网络监视器”图确定导致性能瓶颈的网络问题

    3.服务器资源监控指标:
    内存:
        1 UNIX资源监控中指标内存页交换速率(Paging rate),如果该值偶尔走高,表明当时有线程竞争内存。如果持续很高,则内存可能是瓶颈。也可能是内存访问命中率低。
        2 Windows资源监控中,如果Process\Private Bytes计数器和Process\Working Set计数器的值在长时间内持续升高,同时Memory\Available bytes计数器的值持续降低,则很可能存在内存泄漏。

    内存资源成为系统性能的瓶颈的征兆:
        很高的换页率(high pageout rate);
        进程进入不活动状态;
        交换区所有磁盘的活动次数可高;
        可高的全局系统CPU利用率;
        内存不够出错(out of memory errors)

    处理器:
        1 UNIX资源监控(Windows操作系统同理)中指标CPU占用率(CPU utilization),如果该值持续超过95%,表明瓶颈是CPU。可以考虑增加一个处理器或换一个更快的处理器。如果服务器专用于SQL Server,可接受的最大上限是80-85%
        合理使用的范围在60%至70%。
        2 Windows资源监控中,如果System\Processor Queue Length大于2,而处理器利用率(Processor Time)一直很低,则存在着处理器阻塞。

    CPU资源成为系统性能的瓶颈的征兆:  
         很慢的响应时间(slow response time)
         CPU空闲时间为零(zero percent idle CPU)
         过高的用户占用CPU时间(high percent user CPU)
         过高的系统占用CPU时间(high percent system CPU)
        长时间的有很长的运行进程队列(large run queue size sustained over time)

    磁盘I/O:
        1 UNIX资源监控(Windows操作系统同理)中指标磁盘交换率(Disk rate),如果该参数值一直很高,表明I/O有问题。可考虑更换更快的硬盘系统。
        2 Windows资源监控中,如果 Disk Time和Avg.Disk Queue Length的值很高,而Page Reads/sec页面读取操作速率很低,则可能存在磁盘瓶径。

    I/O资源成为系统性能的瓶颈的征兆 :
         过高的磁盘利用率(high disk utilization)
        太长的磁盘等待队列(large disk queue length)
        等待磁盘I/O的时间所占的百分率太高(large percentage of time waiting for disk I/O)
        太高的物理I/O速率:large physical I/O rate(not sufficient in itself)
        过低的缓存命中率(low buffer cache hit ratio(not sufficient in itself))
        太长的运行进程队列,但CPU却空闲(large run queue with idle CPU)

    4.数据库服务器:
    SQL Server数据库:
        1 SQLServer资源监控中指标缓存点击率(Cache Hit Ratio),该值越高越好。如果持续低于80%,应考虑增加内存。
        2 如果Full Scans/sec(全表扫描/秒)计数器显示的值比1或2高,则应分析你的查询以确定是否确实需要全表扫描,以及SQL查询是否可以被优化。
        3 Number of Deadlocks/sec(死锁的数量/秒):死锁对应用程序的可伸缩性非常有害,并且会导致恶劣的用户体验。该计数器的值必须为0。
       4 Lock Requests/sec(锁请求/秒),通过优化查询来减少读取次数,可以减少该计数器的值。

    Oracle数据库:
      1 如果自由内存接近于0而且库快存或数据字典快存的命中率小于0.90,那么需要增加SHARED_POOL_SIZE的大小。
        快存(共享SQL区)和数据字典快存的命中率:
       select(sum(pins-reloads))/sum(pins) from v$librarycache;
        select(sum(gets-getmisses))/sum(gets) from v$rowcache;
        自由内存:    select * from v$sgastat where name=’free memory’;
    2 如果数据的缓存命中率小于0.90,那么需要加大DB_BLOCK_BUFFERS参数的值(单位:块)。
      缓冲区高速缓存命中率:
        select name,value from v$sysstat where name in ('db block gets’,
        'consistent gets','physical reads') ;
        Hit Ratio = 1-(physical reads / ( db block gets + consistent gets))
    3 如果日志缓冲区申请的值较大,则应加大LOG_BUFFER参数的值。
        日志缓冲区的申请情况 :
         select name,value from v$sysstat where name = 'redo log space requests' ;
    4 如果内存排序命中率小于0.95,则应加大SORT_AREA_SIZE以避免磁盘排序 。
       内存排序命中率 :
         select round((100*b.value)/decode((a.value+b.value), 0, 1, (a.value+b.value)), 2)from v$sysstat a, v$sysstat b where a.name='sorts (disk)' and b.name='sorts (memory)'

     

     

  • Yahoo!网站性能最佳体验的34条黄金守则

    2008-10-28 10:02:32

    Yahoo!的Exceptional Performance团队为改善Web性能带来最佳实践。他们为此进行了一系列的实验、开发了各种工具、写了大量的文章和博客并在各种会议上参与探讨。最佳实践的核心就是旨在提高网站性能。
    Excetional Performance团队总结出了一系列可以提高网站速度的方法。可以分为7大类34条。包括内容、服务器、cookie、CSS、Javascrīpt、图片、移动应用等七部分。

    其中内容部分一共十条建议:

    一、内容部分

    尽量减少HTTP请求
    减少DNS查找
    避免跳转
    缓存Ajxa
    推迟加载
    提前加载
    减少DOM元素数量
    用域名划分页面内容
    使frame数量最少
    避免404错误

    1、尽量减少HTTP请求次数
          终端用户响应的时间中,有80%用于下载各项内容。这部分时间包括下载页面中的图像、样式表、脚本、Flash等。通过减少页面中的元素可以减少HTTP请求的次数。这是提高网页速度的关键步骤。
          减少页面组件的方法其实就是简化页面设计。那么有没有一种方法既能保持页面内容的丰富性又能达到加快响应时间的目的呢?这里有几条减少HTTP请求次数同时又可能保持页面内容丰富的技术。

    合并文件是通过把所有的脚本放到一个文件中来减少HTTP请求的方法,如可以简单地把所有的CSS文件都放入一个样式表中。当脚本或者样式表在不同页面中使用时需要做不同的修改,这可能会相对麻烦点,但即便如此也要把这个方法作为改善页面性能的重要一步。

    CSS Sprites是减少图像请求的有效方法。把所有的背景图像都放到一个图片文件中,然后通过CSS的background-image和background-position属性来显示图片的不同部分;

    图片地图是把多张图片整合到一张图片中。虽然文件的总体大小不会改变,但是可以减少HTTP请求次数。图片地图只有在图片的所有组成部分在页面中是紧挨在一起的时候才能使用,如导航栏。确定图片的坐标和可能会比较繁琐且容易出错,同时使用图片地图导航也不具有可读性,因此不推荐这种方法;

    内联图像是使用data:URL scheme的方法把图像数据加载页面中。这可能会增加页面的大小。把内联图像放到样式表(可缓存)中可以减少HTTP请求同时又避免增加页面文件的大小。但是内联图像现在还没有得到主流浏览器的支持。

         减少页面的HTTP请求次数是你首先要做的一步。这是改进首次访问用户等待时间的最重要的方法。如同Tenni Theurer的他的博客Browser Cahe Usage - Exposed!中所说,HTTP请求在无缓存情况下占去了40%到60%的响应时间。让那些初次访问你网站的人获得更加快速的体验吧!

    2、减少DNS查找次数
            域名系统(DNS)提供了域名和IP的对应关系,就像电话本中人名和他们的电话号码的关系一样。当你在浏览器地址栏中输入
    http://www.dudo.org/时,DNS解析服务器就会返回这个域名对应的IP地址。DNS解析的过程同样也是需要时间的。一般情况下返回给定域名对应的IP地址会花费20到120毫秒的时间。而且在这个过程中浏览器什么都不会做直到DNS查找完毕。

           缓存DNS查找可以改善页面性能。这种缓存需要一个特定的缓存服务器,这种服务器一般属于用户的ISP提供商或者本地局域网控制,但是它同样会在用户使用的计算机上产生缓存。DNS信息会保留在操作系统的DNS缓存中(微软Windows系统中DNS Client Service)。大多数浏览器有独立于操作系统以外的自己的缓存。由于浏览器有自己的缓存记录,因此在一次请求中它不会受到操作系统的影响。

          Internet Explorer默认情况下对DNS查找记录的缓存时间为30分钟,它在注册表中的键值为DnsCacheTimeout。Firefox对DNS的查找记录缓存时间为1分钟,它在配置文件中的选项为network.dnsCacheExpiration(Fasterfox把这个选项改为了1小时)。

          当客户端中的DNS缓存都为空时(浏览器和操作系统都为空),DNS查找的次数和页面中主机名的数量相同。这其中包括页面中URL、图片、脚本文件、样式表、Flash对象等包含的主机名。减少主机名的数量可以减少DNS查找次数。

          减少主机名的数量还可以减少页面中并行下载的数量。减少DNS查找次数可以节省响应时间,但是减少并行下载却会增加响应时间。我的指导原则是把这些页面中的内容分割成至少两部分但不超过四部分。这种结果就是在减少DNS查找次数和保持较高程度并行下载两者之间的权衡了。

    3、避免跳转
    跳转是使用301和302代码实现的。下面是一个响应代码为301的HTTP头:
          HTTP/1.1 301 Moved Permanently
          Location:
    http://example.com/newuri
          Content-Type: text/html
          浏览器会把用户指向到Location中指定的URL。头文件中的所有信息在一次跳转中都是必需的,内容部分可以为空。不管他们的名称,301和302响应都不会被缓存除非增加一个额外的头选项,如Expires或者Cache-Control来指定它缓存。<meat />元素的刷新标签和Javascrīpt也可以实现URL的跳转,但是如果你必须要跳转的时候,最好的方法就是使用标准的3XXHTTP状态代码,这主要是为了确保“后退”按钮可以正确地使用。

          但是要记住跳转会降低用户体验。在用户和HTML文档中间增加一个跳转,会拖延页面中所有元素的显示,因为在HTML文件被加载前任何文件(图像、Flash等)都不会被下载。

          有一种经常被网页开发者忽略却往往十分浪费响应时间的跳转现象。这种现象发生在当URL本该有斜杠(/)却被忽略掉时。例如,当我们要访问http://astrology.yahoo.com/astrology 时,实际上返回的是一个包含301代码的跳转,它指向的是http://astrology.yahoo.com/astrology/  (注意末尾的斜杠)。在Apache服务器中可以使用Alias 或者 mod_rewrite或者the DirectorySlash来避免。

          连接新网站和旧网站是跳转功能经常被用到的另一种情况。这种情况下往往要连接网站的不同内容然后根据用户的不同类型(如浏览器类型、用户账号所属类型)来进行跳转。使用跳转来实现两个网站的切换十分简单,需要的代码量也不多。尽管使用这种方法对于开发者来说可以降低复杂程度,但是它同样降低用户体验。一个可替代方法就是如果两者在同一台服务器上时使用Alias和mod_rewrite和实现。如果是因为域名的不同而采用跳转,那么可以通过使用Alias或者mod_rewirte建立CNAME(保存一个域名和另外一个域名之间关系的DNS记录)来替代。

    4、可缓存的AJAX
          Ajax经常被提及的一个好处就是由于其从后台服务器传输信息的异步性而为用户带来的反馈的即时性。但是,使用Ajax并不能保证用户不会在等待异步的Javascrīpt和XML响应上花费时间。在很多应用中,用户是否需要等待响应取决于Ajax如何来使用。例如,在一个基于Web的Email客户端中,用户必须等待Ajax返回符合他们条件的邮件查询结果。记住一点,“异步”并不异味着“即时”,这很重要。

          为了提高性能,优化Ajax响应是很重要的。提高Ajxa性能的措施中最重要的方法就是使响应具有可缓存性,具体的讨论可以查看Add an Expires or a Cache-Control Header。其它的几条规则也同样适用于Ajax:
        Gizp压缩文件
        减少DNS查找次数
        精简Javascrīpt
        避免跳转
        配置ETags

         让我们来看一个例子:一个Web2.0的Email客户端会使用Ajax来自动完成对用户地址薄的下载。如果用户在上次使用过Email web应用程序后没有对地址薄作任何的修改,而且Ajax响应通过Expire或者Cacke-Control头来实现缓存,那么就可以直接从上一次的缓存中读取地址薄了。必须告知浏览器是使用缓存中的地址薄还是发送一个新的请求。这可以通过为读取地址薄的Ajax URL增加一个含有上次编辑时间的时间戳来实现,例如,&t=11900241612等。如果地址薄在上次下载后没有被编辑过,时间戳就不变,则从浏览器的缓存中加载从而减少了一次HTTP请求过程。如果用户修改过地址薄,时间戳就会用来确定新的URL和缓存响应并不匹配,浏览器就会重要请求更新地址薄。
            即使你的Ajxa响应是动态生成的,哪怕它只适用于一个用户,那么它也应该被缓存起来。这样做可以使你的Web2.0应用程序更加快捷。

    5、推迟加载内容
            你可以仔细看一下你的网页,问问自己“哪些内容是页面呈现时所必需首先加载的?哪些内容和结构可以稍后再加载?
            把整个过程按照onload事件分隔成两部分,Javascrīpt是一个理想的选择。例如,如果你有用于实现拖放和动画的Javascrīpt,那么它就以等待稍后加载,因为页面上的拖放元素是在初始化呈现之后才发生的。其它的例如隐藏部分的内容(用户操作之后才显现的内容)和处于折叠部分的图像也可以推迟加载
            工具可以节省你的工作量:YUI Image Loader可以帮你推迟加载折叠部分的图片,YUI Get utility是包含JS和 CSS的便捷方法。比如你可以打开Firebug的Net选项卡看一下Yahoo的首页。
            当性能目标和其它网站开发实践一致时就会相得益彰。这种情况下,通过程序提高网站性能的方法告诉我们,在支持Javascrīpt的情况下,可以先去除用户体验,不过这要保证你的网站在没有Javascrīpt也可以正常运行。在确定页面运行正常后,再加载脚本来实现如拖放和动画等更加花哨的效果。

    6、预加载
            预加载和后加载看起来似乎恰恰相反,但实际上预加载是为了实现另外一种目标。预加载是在浏览器空闲时请求将来可能会用到的页面内容(如图像、样式表和脚本)。使用这种方法,当用户要访问下一个页面时,页面中的内容大部分已经加载到缓存中了,因此可以大大改善访问速度。

    下面提供了几种预加载方法:
    无条件加载:触发onload事件时,直接加载额外的页面内容。以Google.com为例,你可以看一下它的spirit image图像是怎样在onload中加载的。这个spirit image图像在google.com主页中是不需要的,但是却可以在搜索结果页面中用到它。
    有条件加载:根据用户的操作来有根据地判断用户下面可能去往的页面并相应的预加载页面内容。在search.yahoo.com中你可以看到如何在你输入内容时加载额外的页面内容。
    有预期的加载:载入重新设计过的页面时使用预加载。这种情况经常出现在页面经过重新设计后用户抱怨“新的页面看起来很酷,但是却比以前慢”。问题可能出在用户对于你的旧站点建立了完整的缓存,而对于新站点却没有任何缓存内容。因此你可以在访问新站之前就加载一部内容来避免这种结果的出现。在你的旧站中利用浏览器的空余时间加载新站中用到的图像的和脚本来提高访问速度。

    7、减少DOM元素数量
            一个复杂的页面意味着需要下载更多数据,同时也意味着Javascrīpt遍历DOM的效率越慢。比如当你增加一个事件句柄时在500和5000个DOM元素中循环效果肯定是不一样的。
           大量的DOM元素的存在意味着页面中有可以不用移除内容只需要替换元素标签就可以精简的部分。你在页面布局中使用表格了吗?你有没有仅仅为了布局而引入更多的<div>元素呢?也许会存在一个适合或者在语意是更贴切的标签可以供你使用。
            YUI CSS utilities可以给你的布局带来巨大帮助:grids.css可以帮你实现整体布局,font.css和reset.css可以帮助你移除浏览器默认格式。它提供了一个重新审视你页面中标签的机会,比如只有在语意上有意义时才使用<div>,而不是因为它具有换行效果才使用它。
          DOM元素数量很容易计算出来,只需要在Firebug的控制台内输入:
    document.getElementsByTagName('*').length
            那么多少个DOM元素算是多呢?这可以对照有很好标记使用的类似页面。比如Yahoo!主页是一个内容非常多的页面,但是它只使用了700个元素(HTML标签)。

    8、根据域名划分页面内容
          把页面内容划分成若干部分可以使你最大限度地实现平行下载。由于DNS查找带来的影响你首先要确保你使用的域名数量在2个到4个之间。例如,你可以把用到的HTML内容和动态内容放在
    www.example.org上,而把页面各种组件(图片、脚本、CSS)分别存放在statics1.example.org和statics.example.org上。
    你可在Tenni Theurer和Patty Chi合写的文章Maximizing Parallel Downloads in the Carpool Lane找到更多相关信息。

    9、使iframe的数量最小
          ifrmae元素可以在父文档中插入一个新的HTML文档。了解iframe的工作理然后才能更加有效地使用它,这一点很重要。
    <iframe>优点:

    解决加载缓慢的第三方内容如图标和广告等的加载问题
    Security sandbox
    并行加载脚本
    <iframe>的缺点:

    即时内容为空,加载也需要时间
    会阻止页面加载
    没有语意

    10、不要出现404错误
          HTTP请求时间消耗是很大的,因此使用HTTP请求来获得一个没有用处的响应(例如404没有找到页面)是完全没有必要的,它只会降低用户体验而不会有一点好处。
          有些站点把404错误响应页面改为“你是不是要找***”,这虽然改进了用户体验但是同样也会浪费服务器资源(如数据库等)。最糟糕的情况是指向外部Javascrīpt的链接出现问题并返回404代码。首先,这种加载会破坏并行加载;其次浏览器会把试图在返回的404响应内容中找到可能有用的部分当作Javascrīpt代码来执行。

     

    转载自:http://www.dudo.org/article.asp?id=215

      在本系列的第一节中,讲了提高网站性能中网站“内容”有关的10条原则。除了在网站在内容上的改进外,在网站服务器端上也有需要注意和改进的地方,它们包括:

    使用内容分发网络
    为文件头指定Expires或Cache-Control
    Gzip压缩文件内容
    配置ETag
    尽早刷新输出缓冲
    使用GET来完成AJAX请求

    11、使用内容分发网络
          用户与你网站服务器的接近程度会影响响应时间的长短。把你的网站内容分散到多个、处于不同地域位置的服务器上可以加快下载速度。但是首先我们应该做些什么呢?
          按地域布置网站内容的第一步并不是要尝试重新架构你的网站让他们在分发服务器上正常运行。根据应用的需求来改变网站结构,这可能会包括一些比较复杂的任务,如在服务器间同步Session状态和合并数据库更新等。要想缩短用户和内容服务器的距离,这些架构步骤可能是不可避免的。
          要记住,在终端用户的响应时间中有80%到90%的响应时间用于下载图像、样式表、脚本、Flash等页面内容。这就是网站性能黄金守则。和重新设计你的应用程序架构这样比较困难的任务相比,首先来分布静态内容会更好一点。这不仅会缩短响应时间,而且对于内容分发网络来说它更容易实现。
          内容分发网络(Content Delivery Network,CDN)是由一系列分散到各个不同地理位置上的Web服务器组成的,它提高了网站内容的传输速度。用于向用户传输内容的服务器主要是根据和用户在网络上的靠近程度来指定的。例如,拥有最少网络跳数(network hops)和响应速度最快的服务器会被选定。
          一些大型的网络公司拥有自己的CDN,但是使用像Akamai Technologies,Mirror Image Internet, 或者Limelight Networks这样的CDN服务成本却非常高。对于刚刚起步的企业和个人网站来说,可能没有使用CDN的成本预算,但是随着目标用户群的不断扩大和更加全球化,CDN就是实现快速响应所必需的了。以Yahoo来说,他们转移到CDN上的网站程序静态内容节省了终端用户20%以上的响应时间。使用CDN是一个只需要相对简单地修改代码实现显著改善网站访问速度的方法。

    12、为文件头指定Expires或Cache-Control
          这条守则包括两方面的内容:
    对于静态内容:设置文件头过期时间Expires的值为“Never expire”(永不过期)
    对于动态内容:使用恰当的Cache-Control文件头来帮助浏览器进行有条件的请求
          网页内容设计现在越来越丰富,这就意味着页面中要包含更多的脚本、样式表、图片和Flash。第一次访问你页面的用户就意味着进行多次的HTTP请求,但是通过使用Expires文件头就可以使这样内容具有缓存性。它避免了接下来的页面访问中不必要的HTTP请求。Expires文件头经常用于图像文件,但是应该在所有的内容都使用他,包括脚本、样式表和Flash等。
          浏览器(和代理)使用缓存来减少HTTP请求的大小和次数以加快页面访问速度。Web服务器在HTTP响应中使用Expires文件头来告诉客户端内容需要缓存多长时间。下面这个例子是一个较长时间的Expires文件头,它告诉浏览器这个响应直到2010年4月15日才过期。
          Expires: Thu, 15 Apr 2010 20:00:00 GMT
          如果你使用的是Apache服务器,可以使用ExpiresDefault来设定相对当前日期的过期时间。下面这个例子是使用ExpiresDefault来设定请求时间后10年过期的文件头:
          ExpiresDefault "access plus 10 years"
          要切记,如果使用了Expires文件头,当页面内容改变时就必须改变内容的文件名。依Yahoo!来说我们经常使用这样的步骤:在内容的文件名中加上版本号,如yahoo_2.0.6.js。
          使用Expires文件头只有会在用户已经访问过你的网站后才会起作用。当用户首次访问你的网站时这对减少HTTP请求次数来说是无效的,因为浏览器的缓存是空的。因此这种方法对于你网站性能的改进情况要依据他们“预缓存”存在时对你页面的点击频率(“预缓存”中已经包含了页面中的所有内容)。Yahoo!建立了一套测量方法,我们发现所有的页面浏览量中有75~85%都有“预缓存”。通过使用Expires文件头,增加了缓存在浏览器中内容的数量,并且可以在用户接下来的请求中再次使用这些内容,这甚至都不需要通过用户发送一个字节的请求。

    13、Gzip压缩文件内容
          网络传输中的HTTP请求和应答时间可以通过前端机制得到显著改善。的确,终端用户的带宽、互联网提供者、与对等交换点的靠近程度等都不是网站开发者所能决定的。但是还有其他因素影响着响应时间。通过减小HTTP响应的大小可以节省HTTP响应时间。
          从HTTP/1.1开始,web客户端都默认支持HTTP请求中有Accept-Encoding文件头的压缩格式:  
          Accept-Encoding: gzip, deflate
          如果web服务器在请求的文件头中检测到上面的代码,就会以客户端列出的方式压缩响应内容。Web服务器把压缩方式通过响应文件头中的Content-Encoding来返回给浏览器。
          Content-Encoding: gzip
          Gzip是目前最流行也是最有效的压缩方式。这是由GNU项目开发并通过RFC 1952来标准化的。另外仅有的一个压缩格式是deflate,但是它的使用范围有限效果也稍稍逊色。
          Gzip大概可以减少70%的响应规模。目前大约有90%通过浏览器传输的互联网交换支持gzip格式。如果你使用的是Apache,gzip模块配置和你的版本有关:Apache 1.3使用mod_zip,而Apache 2.x使用moflate。
          浏览器和代理都会存在这样的问题:浏览器期望收到的和实际接收到的内容会存在不匹配的现象。幸好,这种特殊情况随着旧式浏览器使用量的减少在减少。Apache模块会通过自动添加适当的Vary响应文件头来避免这种状况的出现。
          服务器根据文件类型来选择需要进行gzip压缩的文件,但是这过于限制了可压缩的文件。大多数web服务器会压缩HTML文档。对脚本和样式表进行压缩同样也是值得做的事情,但是很多web服务器都没有这个功能。实际上,压缩任何一个文本类型的响应,包括XML和JSON,都值得的。图像和PDF文件由于已经压缩过了所以不能再进行gzip压缩。如果试图gizp压缩这些文件的话不但会浪费CPU资源还会增加文件的大小。
          Gzip压缩所有可能的文件类型是减少文件体积增加用户体验的简单方法。

    14、配置ETag
          Entity tags(ETags)(实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制(“实体”就是所说的“内容”,包括图片、脚本、样式表等)。增加ETag为实体的验证提供了一个比使用“last-modified date(上次编辑时间)”更加灵活的机制。Etag是一个识别内容版本号的唯一字符串。唯一的格式限制就是它必须包含在双引号内。原始服务器通过含有ETag文件头的响应指定页面内容的ETag。
          HTTP/1.1 200 OK
          Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT
          ETag: "10c24bc-4ab-457e1c1f"
          Content-Length: 12195
          稍后,如果浏览器要验证一个文件,它会使用If-None-Match文件头来把ETag传回给原始服务器。在这个例子中,如果ETag匹配,就会返回一个304状态码,这就节省了12195字节的响应。      GET /i/yahoo.gif HTTP/1.1
          Host: us.yimg.com
          If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT
          If-None-Match: "10c24bc-4ab-457e1c1f"
          HTTP/1.1 304 Not Modified
          ETag的问题在于,它是根据可以辨别网站所在的服务器的具有唯一性的属性来生成的。当浏览器从一台服务器上获得页面内容后到另外一台服务器上进行验证时ETag就会不匹配,这种情况对于使用服务器组和处理请求的网站来说是非常常见的。默认情况下,Apache和IIS都会把数据嵌入ETag中,这会显著减少多服务器间的文件验证冲突。
          Apache 1.3和2.x中的ETag格式为inode-size-timestamp。即使某个文件在不同的服务器上会处于相同的目录下,文件大小、权限、时间戳等都完全相同,但是在不同服务器上他们的内码也是不同的。
          IIS 5.0和IIS 6.0处理ETag的机制相似。IIS中的ETag格式为Filetimestamp:ChangeNumber。用ChangeNumber来跟踪IIS配置的改变。网站所用的不同IIS服务器间ChangeNumber也不相同。 不同的服务器上的Apache和IIS即使对于完全相同的内容产生的ETag在也不相同,用户并不会接收到一个小而快的304响应;相反他们会接收一个正常的200响应并下载全部内容。如果你的网站只放在一台服务器上,就不会存在这个问题。但是如果你的网站是架设在多个服务器上,并且使用Apache和IIS产生默认的ETag配置,你的用户获得页面就会相对慢一点,服务器会传输更多的内容,占用更多的带宽,代理也不会有效地缓存你的网站内容。即使你的内容拥有Expires文件头,无论用户什么时候点击“刷新”或者“重载”按钮都会发送相应的GET请求。
          如果你没有使用ETag提供的灵活的验证模式,那么干脆把所有的ETag都去掉会更好。Last-Modified文件头验证是基于内容的时间戳的。去掉ETag文件头会减少响应和下次请求中文件的大小。微软的这篇支持文稿讲述了如何去掉ETag。在Apache中,只需要在配置文件中简单添加下面一行代码就可以了:
          FileETag none

    15、尽早刷新输出缓冲
          当用户请求一个页面时,无论如何都会花费200到500毫秒用于后台组织HTML文件。在这期间,浏览器会一直空闲等待数据返回。在PHP中,你可以使用flush()方法,它允许你把已经编译的好的部分HTML响应文件先发送给浏览器,这时浏览器就会可以下载文件中的内容(脚本等)而后台同时处理剩余的HTML页面。这样做的效果会在后台烦恼或者前台较空闲时更加明显。
          输出缓冲应用最好的一个地方就是紧跟在<head />之后,因为HTML的头部分容易生成而且头部往往包含CSS和Javascrīpt文件,这样浏览器就可以在后台编译剩余HTML的同时并行下载它们。 例子:

          ... <!-- css, js -->
        </head>
        <?php flush(); ?>
        <body>
          ... <!-- content -->

    为了证明使用这项技术的好处,Yahoo!搜索率先研究并完成了用户测试。

    16、使用GET来完成AJAX请求
          Yahoo!Mail团队发现,当使用XMLHttpRequest时,浏览器中的POST方法是一个“两步走”的过程:首先发送文件头,然后才发送数据。因此使用GET最为恰当,因为它只需发送一个TCP包(除非你有很多cookie)。IE中URL的最大长度为2K,因此如果你要发送一个超过2K的数据时就不能使用GET了。
          一个有趣的不同就是POST并不像GET那样实际发送数据。根据HTTP规范,GET意味着“获取”数据,因此当你仅仅获取数据时使用GET更加有意义(从语意上讲也是如此),相反,发送并在服务端保存数据时使用POST。

     

    转载自:http://www.dudo.org/article.asp?id=216


     在第一部分和第二部分中我们分别介绍了改善网站性能中页面内容和服务器的几条守则,除此之外,Javascrīpt和CSS也是我们页面中经常用到的内容,对它们的优化也提高网站性能的重要方面:
    CSS:

    把样式表置于顶部
    避免使用CSS表达式(Expression)
    使用外部Javascrīpt和CSS
    削减Javascrīpt和CSS
    http://www.dudo.org/article.asp?id=216#link
    避免使用滤镜
    Javascrīpt

    把脚本置于页面底部
    使用外部Javascrīpt和CSS
    削减Javascrīpt和CSS
    剔除重复脚本
    减少DOM访问
    开发智能事件处理程序

    17、把样式表置于顶部
          在研究Yahoo!的性能表现时,我们发现把样式表放到文档的<head />内部似乎会加快页面的下载速度。这是因为把样式表放到<head />内会使页面有步骤的加载显示。
          注重性能的前端服务器往往希望页面有秩序地加载。同时,我们也希望浏览器把已经接收到内容尽可能显示出来。这对于拥有较多内容的页面和网速较慢的用户来说特别重要。向用户返回可视化的反馈,比如进程指针,已经有了较好的研究并形成了正式文档。在我们的研究中HTML页面就是进程指针。当浏览器有序地加载文件头、导航栏、顶部的logo等对于等待页面加载的用户来说都可以作为可视化的反馈。这从整体上改善了用户体验。
          把样式表放在文档底部的问题是在包括Internet Explorer在内的很多浏览器中这会中止内容的有序呈现。浏览器中止呈现是为了避免样式改变引起的页面元素重绘。用户不得不面对一个空白页面。
          HTML规范清楚指出样式表要放包含在页面的<head />区域内:“和<a />不同,<link />只能出现在文档的<head />区域内,尽管它可以多次使用它”。无论是引起白屏还是出现没有样式化的内容都不值得去尝试。最好的方案就是按照HTML规范在文档<head />内加载你的样式表。

    18、避免使用CSS表达式(Expression)
          CSS表达式是动态设置CSS属性的强大(但危险)方法。Internet Explorer从第5个版本开始支持CSS表达式。下面的例子中,使用CSS表达式可以实现隔一个小时切换一次背景颜色:
          background-color: expression( (new Date()).getHours()%2 ? "#B8D4FF" : "#F08A00" );
    如上所示,expression中使用了Javascrīpt表达式。CSS属性根据Javascrīpt表达式的计算结果来设置。expression方法在其它浏览器中不起作用,因此在跨浏览器的设计中单独针对Internet Explorer设置时会比较有用。
          表达式的问题就在于它的计算频率要比我们想象的多。不仅仅是在页面显示和缩放时,就是在页面滚动、乃至移动鼠标时都会要重新计算一次。给CSS表达式增加一个计数器可以跟踪表达式的计算频率。在页面中随便移动鼠标都可以轻松达到10000次以上的计算量。
          一个减少CSS表达式计算次数的方法就是使用一次性的表达式,它在第一次运行时将结果赋给指定的样式属性,并用这个属性来代替CSS表达式。如果样式属性必须在页面周期内动态地改变,使用事件句柄来代替CSS表达式是一个可行办法。如果必须使用CSS表达式,一定要记住它们要计算成千上万次并且可能会对你页面的性能产生影响。

    19、使用外部Javascrīpt和CSS
          很多性能规则都是关于如何处理外部文件的。但是,在你采取这些措施前你可能会问到一个更基本的问题:Javascrīpt和CSS是应该放在外部文件中呢还是把它们放在页面本身之内呢?
          在实际应用中使用外部文件可以提高页面速度,因为Javascrīpt和CSS文件都能在浏览器中产生缓存。内置在HTML文档中的Javascrīpt和CSS则会在每次请求中随HTML文档重新下载。这虽然减少了HTTP请求的次数,却增加了HTML文档的大小。从另一方面来说,如果外部文件中的Javascrīpt和CSS被浏览器缓存,在没有增加HTTP请求次数的同时可以减少HTML文档的大小。
          关键问题是,外部Javascrīpt和CSS文件缓存的频率和请求HTML文档的次数有关。虽然有一定的难度,但是仍然有一些指标可以一测量它。如果一个会话中用户会浏览你网站中的多个页面,并且这些页面中会重复使用相同的脚本和样式表,缓存外部文件就会带来更大的益处。
          许多网站没有功能建立这些指标。对于这些网站来说,最好的坚决方法就是把Javascrīpt和CSS作为外部文件引用。比较适合使用内置代码的例外就是网站的主页,如Yahoo!主页和My Yahoo!。主页在一次会话中拥有较少(可能只有一次)的浏览量,你可以发现内置Javascrīpt和CSS对于终端用户来说会加快响应时 间。
          对于拥有较大浏览量的首页来说,有一种技术可以平衡内置代码带来的HTTP请求减少与通过使用外部文件进行缓存带来的好处。其中一个就是在首页中内置Javascrīpt和CSS,但是在页面下载完成后动态下载外部文件,在子页面中使用到这些文件时,它们已经缓存到浏览器了。

    20、削减Javascrīpt和CSS
          精简是指从去除代码不必要的字符减少文件大小从而节省下载时间。消减代码时,所有的注释、不需要的空白字符(空格、换行、tab缩进)等都要去掉。在Javascrīpt中,由于需要下载的文件体积变小了从而节省了响应时间。精简Javascrīpt中目前用到的最广泛的两个工具是JSMin和YUI Compressor。YUI Compressor还可用于精简CSS。
          混淆是另外一种可用于源代码优化的方法。这种方法要比精简复杂一些并且在混淆的过程更易产生问题。在对美国前10大网站的调查中发现,精简也可以缩小原来代码体积的21%,而混淆可以达到25%。尽管混淆法可以更好地缩减代码,但是对于Javascrīpt来说精简的风险更小。
          除消减外部的脚本和样式表文件外,<scrīpt>和<style>代码块也可以并且应该进行消减。即使你用Gzip压缩过脚本和样式表,精简这些文件仍然可以节省5%以上的空间。由于Javascrīpt和CSS的功能和体积的增加,消减代码将会获得益处。

    21、用<link>代替@import
          前面的最佳实现中提到CSS应该放置在顶端以利于有序加载呈现。
          在IE中,页面底部@import和使用<link>作用是一样的,因此最好不要使用它。

    22、避免使用滤镜
          IE独有属性AlphaImageLoader用于修正7.0以下版本中显示PNG图片的半透明效果。这个滤镜的问题在于浏览器加载图片时它会终止内容的呈现并且冻结浏览器。在每一个元素(不仅仅是图片)它都会运算一次,增加了内存开支,因此它的问题是多方面的。
          完全避免使用AlphaImageLoader的最好方法就是使用PNG8格式来代替,这种格式能在IE中很好地工作。如果你确实需要使用AlphaImageLoader,请使用下划线_filter又使之对IE7以上版本的用户无效。

    23、把脚本置于页面底部
          脚本带来的问题就是它阻止了页面的平行下载。HTTP/1.1 规范建议,浏览器每个主机名的并行下载内容不超过两个。如果你的图片放在多个主机名上,你可以在每个并行下载中同时下载2个以上的文件。但是当下载脚本时,浏览器就不会同时下载其它文件了,即便是主机名不相同。
          在某些情况下把脚本移到页面底部可能不太容易。比如说,如果脚本中使用了document.write来插入页面内容,它就不能被往下移动了。这里可能还会有作用域的问题。很多情况下,都会遇到这方面的问题。
          一个经常用到的替代方法就是使用延迟脚本。DEFER属性表明脚本中没有包含document.write,它告诉浏览器继续显示。不幸的是,Firefox并不支持DEFER属性。在Internet Explorer中,脚本可能会被延迟但效果也不会像我们所期望的那样。如果脚本可以被延迟,那么它就可以移到页面的底部。这会让你的页面加载的快一点。

    24、剔除重复脚本
          在同一个页面中重复引用Javascrīpt文件会影响页面的性能。你可能会认为这种情况并不多见。对于美国前10大网站的调查显示其中有两家存在重复引用脚本的情况。有两种主要因素导致一个脚本被重复引用的奇怪现象发生:团队规模和脚本数量。如果真的存在这种情况,重复脚本会引起不必要的HTTP请求和无用的Javascrīpt运算,这降低了网站性能。
          在Internet Explorer中会产生不必要的HTTP请求,而在Firefox却不会。在Internet Explorer中,如果一个脚本被引用两次而且它又不可缓存,它就会在页面加载过程中产生两次HTTP请求。即时脚本可以缓存,当用户重载页面时也会产生额外的HTTP请求。
          除增加额外的HTTP请求外,多次运算脚本也会浪费时间。在Internet Explorer和Firefox中不管脚本是否可缓存,它们都存在重复运算Javascrīpt的问题。
          一个避免偶尔发生的两次引用同一脚本的方法是在模板中使用脚本管理模块引用脚本。在HTML页面中使用<scrīpt />标签引用脚本的最常见方法就是:
          <scrīpt type="text/javascrīpt" src="menu_1.0.17.js"></scrīpt>
    在PHP中可以通过创建名为insertscrīpt的方法来替代:
          <?php insertscrīpt("menu.js") ?>
    为了防止多次重复引用脚本,这个方法中还应该使用其它机制来处理脚本,如检查所属目录和为脚本文件名中增加版本号以用于Expire文件头等。

    25、减少DOM访问
          使用Javascrīpt访问DOM元素比较慢,因此为了获得更多的应该页面,应该做到:

    缓存已经访问过的有关元素
    线下更新完节点之后再将它们添加到文档树中
    避免使用Javascrīpt来修改页面布局
          有关此方面的更多信息请查看Julien Lecomte在YUI专题中的文章“高性能Ajax应该程序”。

    26、开发智能事件处理程序
          有时候我们会感觉到页面反应迟钝,这是因为DOM树元素中附加了过多的事件句柄并且些事件句病被频繁地触发。这就是为什么说使用event delegation(事件代理)是一种好方法了。如果你在一个div中有10个按钮,你只需要在div上附加一次事件句柄就可以了,而不用去为每一个按钮增加一个句柄。事件冒泡时你可以捕捉到事件并判断出是哪个事件发出的。
          你同样也不用为了操作DOM树而等待onload事件的发生。你需要做的就是等待树结构中你要访问的元素出现。你也不用等待所有图像都加载完毕。
          你可能会希望用DOMContentLoaded事件来代替onload,但是在所有浏览器都支持它之前你可使用YUI 事件应用程序中的onAvailable方法。
          有关此方面的更多信息请查看Julien Lecomte在YUI专题中的文章“高性能Ajax应该程序”。


    我们在前面的几节中分别讲了提高网站性能中内容、服务器、Javascrīpt和CSS等方面的内容。除此之外,图片和Coockie也是我们网站中几乎不可缺少组成部分,此外随着移动设备的流行,对于移动应用的优化也十分重要。这主要包括:
    Coockie:

    减小Cookie体积
    对于页面内容使用无coockie域名
    图片:

    优化图像
    优化CSS Spirite
    不要在HTML中缩放图像
    favicon.ico要小而且可缓存
    移动应用:

    保持单个内容小于25K
    打包组件成复合文本

    27、减小Cookie体积
          HTTP coockie可以用于权限验证和个性化身份等多种用途。coockie内的有关信息是通过HTTP文件头来在web服务器和浏览器之间进行交流的。因此保持coockie尽可能的小以减少用户的响应时间十分重要。
    有关更多信息可以查看Tenni Theurer和Patty Chi的文章“When the Cookie Crumbles”。这们研究中主要包括:

    去除不必要的coockie
    使coockie体积尽量小以减少对用户响应的影响
    注意在适应级别的域名上设置coockie以便使子域名不受影响
    设置合理的过期时间。较早地Expire时间和不要过早去清除coockie,都会改善用户的响应时间。
    28、对于页面内容使用无coockie域名
          当浏览器在请求中同时请求一张静态的图片和发送coockie时,服务器对于这些coockie不会做任何地使用。因此他们只是因为某些负面因素而创建的网络传输。所有你应该确定对于静态内容的请求是无coockie的请求。创建一个子域名并用他来存放所有静态内容。
          如果你的域名是
    www.example.org,你可以在static.example.org上存在静态内容。但是,如果你不是在www.example.org上而是在顶级域名example.org设置了coockie,那么所有对于static.example.org的请求都包含coockie。在这种情况下,你可以再重新购买一个新的域名来存在静态内容,并且要保持这个域名是无coockie的。Yahoo!使用的是ymig.com,YouTube使用的是ytimg.com,Amazon使用的是images-anazon.com等等。
          使用无coockie域名存在静态内容的另外一个好处就是一些代理(服务器)可能会拒绝对coockie的内容请求进行缓存。一个相关的建议就是,如果你想确定应该使用example.org还是
    www.example.org作为你的一主页,你要考虑到coockie带来的影响。忽略掉www会使你除了把coockie设置到*.example.org(*是泛域名解析,代表了所有子域名译者dudo注)外没有其它选择,因此出于性能方面的考虑最好是使用带有www的子域名并且在它上面设置coockie。

    29、优化图像
          设计人员完成对页面的设计之后,不要急于将它们上传到web服务器,这里还需要做几件事:

    你可以检查一下你的GIF图片中图像颜色的数量是否和调色板规格一致。 使用imagemagick中下面的命令行很容易检查:
    identify -verbose image.gif
    如果你发现图片中只用到了4种颜色,而在调色板的中显示的256色的颜色槽,那么这张图片就还有压缩的空间。
    尝试把GIF格式转换成PNG格式,看看是否节省空间。大多数情况下是可以压缩的。由于浏览器支持有限,设计者们往往不太乐意使用PNG格式的图片,不过这都是过去的事情了。现在只有一个问题就是在真彩PNG格式中的alpha通道半透明问题,不过同样的,GIF也不是真彩格式也不支持半透明。因此GIF能做到的,PNG(PNG8)同样也能做到(除了动画)。下面这条简单的命令可以安全地把GIF格式转换为PNG格式:
    convert image.gif image.png
    “我们要说的是:给PNG一个施展身手的机会吧!”
    在所有的PNG图片上运行pngcrush(或者其它PNG优化工具)。例如:
    pngcrush image.png -rem alla -reduce -brute result.png
    在所有的JPEG图片上运行jpegtran。这个工具可以对图片中的出现的锯齿等做无损操作,同时它还可以用于优化和清除图片中的注释以及其它无用信息(如EXIF信息):
    jpegtran -copy none -optimize -perfect src.jpg dest.jpg
    30、优化CSS Spirite

    在Spirite中水平排列你的图片,垂直排列会稍稍增加文件大小;
    Spirite中把颜色较近的组合在一起可以降低颜色数,理想状况是低于256色以便适用PNG8格式;
    便于移动,不要在Spirite的图像中间留有较大空隙。这虽然不大会增加文件大小但对于用户代理来说它需要更少的内存来把图片解压为像素地图。100x100的图片为1万像素,而1000x1000就是100万像素。

    31、不要在HTML中缩放图像
          不要为了在HTML中设置长宽而使用比实际需要大的图片。如果你需要:
    <img width="100" height="100" src="mycat.jpg" alt="My Cat" />
    那么你的图片(mycat.jpg)就应该是100x100像素而不是把一个500x500像素的图片缩小使用。

    32、favicon.ico要小而且可缓存
          favicon.ico是位于服务器根目录下的一个图片文件。它是必定存在的,因为即使你不关心它是否有用,浏览器也会对它发出请求,因此最好不要返回一个404 Not Found的响应。由于是在同一台服务器上,它每被请求一次coockie就会被发送一次。这个图片文件还会影响下载顺序,例如在IE中当你在onload中请求额外的文件时,favicon会在这些额外内容被加载前下载。
          因此,为了减少favicon.ico带来的弊端,要做到:

    文件尽量地小,最好小于1K
    在适当的时候(也就是你不要打算再换favicon.ico的时候,因为更换新文件时不能对它进行重命名)为它设置Expires文件头。你可以很安全地把Expires文件头设置为未来的几个月。你可以通过核对当前favicon.ico的上次编辑时间来作出判断。
    Imagemagick可以帮你创建小巧的favicon。

    33、保持单个内容小于25K
          这条限制主要是因为iPhone不能缓存大于25K的文件。注意这里指的是解压缩后的大小。由于单纯gizp压缩可能达不要求,因此精简文件就显得十分重要。
          查看更多信息,请参阅Wayne Shea和Tenni Theurer的文件“Performance Research, Part 5: iPhone Cacheability - Making it Stick”。

    34、打包组件成复合文本
          把页面内容打包成复合文本就如同带有多附件的Email,它能够使你在一个HTTP请求中取得多个组件(切记:HTTP请求是很奢侈的)。当你使用这条规则时,首先要确定用户代理是否支持(iPhone就不支持)。

     

  • 一个安全测试的checklist

    2008-10-28 09:58:37

    1. 不登录系统,直接输入登录后的页面的url是否可以访问

      2. 不登录系统,直接输入下载文件的url是否可以下载,如输入http://url/download?name=file是否可以下载文件file

      3. 退出登录后按后退按钮能否访问之前的页面

      4. ID/密码验证方式中能否使用简单密码。如密码标准为6位以上,字母和数字混合,不能包含ID,连续的字母或数字不能超过n位

      5. 重要信息(如密码,身份证号码,信用卡号等)在输入或查询时是否用明文显示;在浏览器地址栏里输入命令javascrīpt:alert(doucument.cookie)时是否有重要信息;在html源码中能否看到重要信息

      6. 手动更改URL中的参数值能否访问没有权限访问的页面。如普通用户对应的url中的参数为l=e,高级用户对应的url中的参数为l=s,以普通用户的身份登录系统后将url中的参数e改为s来访问本没有权限访问的页面

      7. url里不可修改的参数是否可以被修改

      8. 上传与服务器端语言(jsp、asp、php)一样扩展名的文件或exe等可执行文件后,确认在服务器端是否可直接运行

      9. 注册用户时是否可以以'--,' or 1=1 --等做为用户名

      10. 传送给服务器的参数(如查询关键字、url中的参数等)中包含特殊字符(','and 1=1 --,' and 1=0 --,'or 1=0 --)时是否可以正常处理

      11. 执行新增操作时,在所有的输入框中输入脚本标签(<scrīpt>alert("")</scrīpt>)后能否保存

      12. 在url中输入下面的地址是否可以下载:http://url/download.jsp?file=C:\windows\system32\drivers\etc\hosts,http://url/download.jsp?file=/etc/passwd

      13. 是否对session的有效期进行处理

      14. 错误信息中是否含有sql语句、sql错误信息以及web服务器的绝对路径等

      15. ID/密码验证方式中,同一个账号在不同的机器上不能同时登录

      16. ID/密码验证方式中,连续数次输入错误密码后该账户是否被锁定

      17. 新增或修改重要信息(密码、身份证号码、信用卡号等)时是否有自动完成功能(在form标签中使用autocomplete=off来关闭自动完成功能)

     

  • 要做好性能测试,该掌握些什么?

    2008-10-28 09:55:25

    1. 精通性能测试的基本概念,过程,方法论,了解性能工程;

    2. 精通1个商业性能测试工具+1个开源性能测试工具,知道工具可以做什么,不可以做什么,以及工具使用中常见的问题和解决思路;

    3. 扎实的计算机专业基础知识,包括计算机组成原理、操作系统、数据库原理、计算机网络原理;

    4. 熟悉至少1个常用的数据库产品,例如SQL Server或者 Oracle,能进行一般的数据库管理操作,熟悉SQL脚本的使用,熟悉常用的数据调优工具和常用的counter;

    5. 熟悉至少一个操作系统的原理,Windows或者Linux都可以,熟悉操作系统的体系架构、操作系统的重要基础概念,以及内存管理、存储/文件系统、驱动/硬件的管理、网络协议的实现及构成、性能的监控方法和原理,熟悉常用的counter;

    6. 熟悉至少一个web server 产品,例如apache,了解一般的配置和常用的counter;

    7. 熟悉至少一个应用服务器产品,例如tomcat,了解一般的配置,熟悉常用的服务器性能监控方法和原理,熟悉常用的counter;

    8. 至少熟悉TCP/IP协议,熟悉HTTP协议,至少见过并了解三层、四层交换或者路由器的使用和配置。了解常用的与网络性能相关的counter;

    9. 了解一般的大型企业应用的部署架构和应用架构;

    10. 了解知名大型web应用、高并发量、高流量、实时响应要求高的超大规模网站的架构和优化历程;

    11. 熟悉统计学的基础知识、常用分析方法以及实验设计方法,了解数学建模相关的知识;

    12. 熟悉专属行业的业务知识和用户场景,例如电信行业的OSS系统所涉及的业务知识和用户场景,证券交易系统所涉及的业务知识和用户场景;

    13. 大量的实际性能测试及优化经验;

    14. 积极的参与到各类圈子、社团的讨论和交流、分享中。

  • 性能测试(并发负载压力)测试分析---转载

    2008-10-11 14:54:36

    分析原则:

     

    • 具体问题具体分析(这是由于不同的应用系统,不同的测试目的,不同的性能关注点)

     

    • 查找瓶颈时按以下顺序,由易到难。

     

              服务器硬件瓶颈

              网络瓶颈(对局域网,可以不考虑)

              服务器操作系统瓶颈(参数配置)

              中间件瓶颈(参数配置,数据库, web 服务器等)

              应用瓶颈( SQL 语句、数据库设计、业务逻辑、算法等)

     

        注:以上过程并不是每个分析中都需要的,要根据测试目的和要求来确定分析的深度。对一些要求低的,我们分析到应用系统在将来大的负载压力(并发用户数、数据量)下,系统的硬件瓶颈在哪儿就够了。

     

    • 分段排除法 很有效

     

    分析的信息来源:

              • 1 根据场景运行过程中的错误提示信息

              • 2 根据测试结果收集到的监控指标数据

     

    一.错误提示分析

     

    分析实例:

    1     • Error: Failed to connect to server “ 10.10.10 .30:8080 ″ : [10060] Connection

    • Error: timed out Error: Server “ 10.10.10 .30 ″ has shut down the connection prematurely

    分析:

    • A 、应用服务死掉。

    (小用户时:程序上的问题。程序上处理数据库的问题)

    • B 、应用服务没有死

    (应用服务参数设置问题)

     

        例:在许多客户端连接 Weblogic 应用服务器被拒绝,而在服务器端没有错误显示,则有可能是 Weblogic 中的 server 元素的 AcceptBacklog 属性值设得过低。如果连接时收到 connection refused 消息,说明应提高该值,每次增加 25 %

     

    • C 、数据库的连接

     

    (1 、在应用服务的性能参数可能太小了 2 、数据库启动的最大连接数(跟硬件的内存有关) )

     

    2 Error: Page download timeout (120 seconds) has expired

     

    分析:可能是以下原因造成

     

              • A 、应用服务参数设置太大导致服务器的瓶颈

              • B 、页面中图片太多

              • C 、在程序处理表的时候检查字段太大多

     

    二.监控指标数据分析

     

    1 .最大并发用户数:

     

    应用系统在当前环境(硬件环境、网络环境、软件环境(参数配置))下能承受的最大并发用户数。

     

              在方案运行中,如果出现了大于 3 个用户的业务操作失败,或出现了服务器 shutdown 的情况,则说明在当前环境下,系统承受不了当前并发用户的负载压力,那么最大并发用户数就是前一个没有出现这种现象的并发用户数。

              如果测得的最大并发用户数到达了性能要求,且各服务器资源情况良好,业务操作响应时间也达到了用户要求,那么 OK 。否则,再根据各服务器的资源情况和业务操作响应时间进一步分析原因所在。

     

    2 .业务操作响应时间:

     

              • 分析方案运行情况应从平均事务响应时间图和事务性能摘要图开始。使用“事务性能摘要”图,可以确定在方案执行期间响应时间过长的事务。

              • 细分事务并分析每个页面组件的性能。查看过长的事务响应时间是由哪些页面组件引起的?问题是否与网络或服务器有关?

              • 如果服务器耗时过长,请使用相应的服务器图确定有问题的服务器度量并查明服务器性能下降的原因。如果网络耗时过长,请使用“网络监视器”图确定导致性能瓶颈的网络问题

     

    3 .服务器资源监控指标:

     

    内存:

     

    1 UNIX 资源监控中指标内存页交换速率( Paging rate ),如果该值偶尔走高,表明当时有线程竞争内存。如果持续很高,则内存可能是瓶颈。也可能是内存访问命中率低。

     

    2 Windows 资源监控中,如果 Process\Private Bytes 计数器和 Process\Working Set 计数器的值在长时间内持续升高,同时 Memory\Available bytes 计数器的值持续降低,则很可能存在内存泄漏。

     

    内存资源成为系统性能的瓶颈的征兆 :

     

              很高的换页率 (high pageout rate);

              进程进入不活动状态 ;

              交换区所有磁盘的活动次数可高 ;

              可高的全局系统 CPU 利用率 ; 

              内存不够出错 (out of memory errors)

     

    处理器:

     

    1 UNIX 资源监控( Windows 操作系统同理)中指标 CPU 占用率( CPU utilization ),如果该值持续超过 95% ,表明瓶颈是 CPU 。可以考虑增加一个处理器或换一个更快的处理器。如果服务器专用于 SQL Server, 可接受的最大上限是 80-85% 

     

    合理使用的范围在 60% 至 70% 。

     

    2 Windows 资源监控中,如果 System\Processor Queue Length 大于 2 ,而处理器利用率( Processor Time )一直很低,则存在着处理器阻塞。

     

    CPU 资源成为系统性能的瓶颈的征兆 : 

     

              很慢的响应时间 (slow response time) 

              CPU 空闲时间为零 (zero percent idle CPU) 

              过高的用户占用 CPU 时间 (high percent user CPU) 

              过高的系统占用 CPU 时间 (high percent system CPU) 

              长时间的有很长的运行进程队列 (large run queue size sustained over time)

     

    磁盘 I/O :

     

    1 UNIX 资源监控( Windows 操作系统同理)中指标磁盘交换率( Disk rate ),如果该参数值一直很高,表明 I/O 有问题。可考虑更换更快的硬盘系统。

     

    2 Windows 资源监控中,如果 Disk Time 和 Avg.Disk Queue Length 的值很高,而 Page Reads/sec 页面读取操作速率很低,则可能存在磁盘瓶径。

     

    I/O 资源成为系统性能的瓶颈的征兆 :

     

              过高的磁盘利用率 (high disk utilization) 

              太长的磁盘等待队列 (large disk queue length) 

              等待磁盘 I/O 的时间所占的百分率太高 (large percentage of time waiting for disk I/O) 

              太高的物理 I/O 速率 :large physical I/O rate(not sufficient in itself) 

              过低的缓存命中率 (low buffer cache hit ratio(not sufficient in itself)) 

              太长的运行进程队列,但 CPU 却空闲 (large run queue with idle CPU)

     

    4 .数据库服务器:

     

    SQL Server 数据库:

     

    1 SQLServer 资源监控中指标缓存点击率( Cache Hit Ratio ),该值越高越好。如果持续低于 80% ,应考虑增加内存。

     

    2 如果 Full Scans/sec (全表扫描 / 秒)计数器显示的值比 1 或 2 高,则应分析你的查询以确定是否确实需要全表扫描,以及 SQL 查询是否可以被优化。  

     

    3 Number of Deadlocks/sec( 死锁的数量 / 秒 ) :死锁对应用程序的可伸缩性非常有害,并且会导致恶劣的用户体验。该计数器的值必须为 0 。

     

    4 Lock Requests/sec( 锁请求 / 秒 ) ,通过优化查询来减少读取次数,可以减少该计数器的值。

     

    Oracle 数据库:

     

    1 如果自由内存接近于 0 而且库快存或数据字典快存的命中率小于 0.90 ,那么需要增加 SHARED_POOL_SIZE 的大小。

     

    快存(共享 SQL 区)和数据字典快存的命中率:  

     

    select(sum(pins-reloads))/sum(pins) from v$librarycache; 

     

    select(sum(gets-getmisses))/sum(gets) from v$rowcache; 

     

    自由内存: select * from v$sgastat where name= ’ free memory ’ ; 

     

    2 如果数据的缓存命中率小于 0.90 ,那么需要加大 DB_BLOCK_BUFFERS 参数的值(单位:块)。

     

    缓冲区高速缓存命中率:

     

    select name,value from v$sysstat where name in (’db block gets’,

     

    ‘ consistent gets’,'physical reads’) ;

     

    Hit Ratio = 1-(physical reads / ( db block gets + consistent gets))

     

    3 如果日志缓冲区申请的值较大,则应加大 LOG_BUFFER 参数的值。

     

    日志缓冲区的申请情况 :

     

    select name,value from v$sysstat where name = ‘redo log space requests’ ;

     

    4 如果内存排序命中率小于 0.95 ,则应加大 SORT_AREA_SIZE 以避免磁盘排序 。

     

    内存排序命中率 :

     

    select round((100*b.value)/decode((a.value+b.value), 0, 1, (a.value+b.value)), 2)from v$sysstat a, v$sysstat b where a.name=’sorts (disk)’ and b.name=’sorts (memory)’

     

    注:上述 SQL Server 和 Oracle 数据库分析,只是一些简单、基本的分析,特别是 Oracle 数据库的分析和优化,是一门专门的技术,进一步的分析可查相关资料。
  • 如何有效的对测试人员进行业绩考核?(转载)

    2008-10-09 15:10:20

    测试人员主要是三个方面。
            第一,整体工作效率。第二,工作结果。第三,过程控制。(针对测试主管或组长)
            1.整体工作效率
            1.1有效工作时间
            主要check指标是每日实际工作时间,按照Ms的标准,一个测试工程师的每天的有效工作时间应该在70%以上。如果只有50%或以下的有效工作时间,那么不能成为好的测试工程师,因为他有能力做得更好。
            1.2是否在制定时间内完成工作任务
            主要check指标是进度偏离度。主要是和测试计划相比,有多少的延期。这个指标计算是:计划时间/实际需用时间。
            当然,本指标未考虑其他因素,如开发人员窝工导致的delay。
            2.工作结果
            2.1测试用例的数量和质量
            a,测试用例的数量
            主要考核指标是用例编写速度,考核办法是测试用例的个数/写用例所用时间。
            b,测试用例的质量
            主要考核指标是用例编写质量,用于考察文档是由有效的指导了测试工作。考核办法是来自用例的bug数目/总bug数目,应该是70%以上才算是质量比较好的用例。
            2.2bug的数量和质量
            a,bug提交的数量
            主要考核指标是提交bug的数量,这个指标根据项目不同而定,不好给出固定经验值。
            b,bug的质量
            主要考核指标是提交bug的质量,即提交的bug,严重程度和,发现路径的复杂程度
            c,发现bug的阶段
            主要考核指标是提交bug的时间段,具体执行是统计在测试的每个阶段,发现bug的比例,特别是严重的bug发现的早晚
            2.3是否及时验证关闭bug
            主要考核指标是验证关闭bug的及时度
            2.4测试自动化程度及收效
            主要考核指标是,测试中自动化运用的含量,也就是测试技术含量,成果如何?
            2.5所负责模块的产品总体质量以及用户反馈
            这个总体质量是产品发布之后一段时间才能得出结论,主要是市场,用户对产品的质量、稳定性、性能的反馈。
    考核的主要指标是两个。
            a,根据市场反馈(由经理定性考核)
            b,根据测试人员提交的bug和用户反馈的bug之间的比例,比例越大,说明测试质量相对越高。当然前提是必须划清楚客户的新需求,或者对spec设计方面的抱怨。
            3.过程改进
            考核点,是纵向对比,相比上一个项目,在质量控制上和测试进度进程上有否进步。包括测试方法,提升质量的手段,测试数据记录,用例更新等等有没有改进。
            该项具体考核方法也是经理来根据测试组在过程中具体表现,来定性打分。
            还包括测试人员在测试过程中的学习能力。这个也是定性。
            4.考核注意事项
            4.1统计bug的注意事项
            5.其它注意事项
            作为考核者要注意以下比例,也许有些没有列入考核内容,但是如下这些点可以指导测试。
            a,测试团队发现的bug和所有bug之间的比例
            b,spec设计造成的bug
            c,重复或者误提交的bug所占的比例
            d,每周发现的bug的趋势图
            e,Bug严重等级的构成比例
            f,Bug从提交到解决的平均需要时间
            g,Bug从解决到关闭的平均需要时间

  • 性能测试(并发负载压力)测试分析-简要篇(转)

    2008-10-08 11:06:26

    在论坛混了多日,发现越来越多的性能测试工程师基本上都能够掌握利用测试工具来作负载压力测试,但多数人对怎样去分析工具收集到的测试结果感到无从下手,下面我就把个人工作中的体会和收集到的有关资料整理出来,希望能对大家分析测试结果有所帮助。

    分析原则:
        • 具体问题具体分析(这是由于不同的应用系统,不同的测试目的,不同的性能关注点)
        • 查找瓶颈时按以下顺序,由易到难。
        服务器硬件瓶颈-〉网络瓶颈(对局域网,可以不考虑)-〉服务器操作系统瓶颈(参数配置)-〉中间件瓶颈(参数配置,数据库,web服务器等)-〉应用瓶颈(SQL语句、数据库设计、业务逻辑、算法等)
        注:以上过程并不是每个分析中都需要的,要根据测试目的和要求来确定分析的深度。对一些要求低的,我们分析到应用系统在将来大的负载压力(并发用户数、数据量)下,系统的硬件瓶颈在哪儿就够了。
        • 分段排除法 很有效

    分析的信息来源:
        •1 根据场景运行过程中的错误提示信息
        •2 根据测试结果收集到的监控指标数据

    一.错误提示分析

    分析实例:
    1 •Error: Failed to connect to server "10.10.10.30:8080": [10060] Connection
      •Error: timed out Error: Server "10.10.10.30" has shut down the connection prematurely

      分析:
    •A、应用服务死掉。
       (小用户时:程序上的问题。程序上处理数据库的问题)
    •B、应用服务没有死
       (应用服务参数设置问题)
        例:在许多客户端连接Weblogic应用服务器被拒绝,而在服务器端没有错误显示,则有可能是Weblogic中的server元素的AcceptBacklog属性值设得过低。如果连接时收到connection refused消息,说明应提高该值,每次增加25%
    •C、数据库的连接
       (1、在应用服务的性能参数可能太小了 2、数据库启动的最大连接数(跟硬件的内存有关))

    2  Error: Page download timeout (120 seconds) has expired

    分析:可能是以下原因造成
    •A、应用服务参数设置太大导致服务器的瓶颈
    •B、页面中图片太多
    •C、在程序处理表的时候检查字段太大多

    二.监控指标数据分析

    1.最大并发用户数:
    应用系统在当前环境(硬件环境、网络环境、软件环境(参数配置))下能承受的最大并发用户数。
    在方案运行中,如果出现了大于3个用户的业务操作失败,或出现了服务器shutdown的情况,则说明在当前环境下,系统承受不了当前并发用户的负载压力,那么最大并发用户数就是前一个没有出现这种现象的并发用户数。
    如果测得的最大并发用户数到达了性能要求,且各服务器资源情况良好,业务操作响应时间也达到了用户要求,那么OK。否则,再根据各服务器的资源情况和业务操作响应时间进一步分析原因所在。

    2.业务操作响应时间:
    • 分析方案运行情况应从平均事务响应时间图和事务性能摘要图开始。使用“事务性能摘要”图,可以确定在方案执行期间响应时间过长的事务。
    • 细分事务并分析每个页面组件的性能。查看过长的事务响应时间是由哪些页面组件引起的?问题是否与网络或服务器有关?
    • 如果服务器耗时过长,请使用相应的服务器图确定有问题的服务器度量并查明服务器性能下降的原因。如果网络耗时过长,请使用“网络监视器”图确定导致性能瓶颈的网络问题
    3.服务器资源监控指标:
    内存:
        1 UNIX资源监控中指标内存页交换速率(Paging rate),如果该值偶尔走高,表明当时有线程竞争内存。如果持续很高,则内存可能是瓶颈。也可能是内存访问命中率低。

        2 Windows资源监控中,如果Process\Private Bytes计数器和Process\Working Set计数器的值在长时间内持续升高,同时Memory\Available bytes计数器的值持续降低,则很可能存在内存泄漏。

    内存资源成为系统性能的瓶颈的征兆:
        很高的换页率(high pageout rate);
        进程进入不活动状态;
        交换区所有磁盘的活动次数可高;
        可高的全局系统CPU利用率;
        内存不够出错(out of memory errors)

    处理器:
        1 UNIX资源监控(Windows操作系统同理)中指标CPU占用率(CPU utilization),如果该值持续超过95%,表明瓶颈是CPU。可以考虑增加一个处理器或换一个更快的处理器。如果服务器专用于SQL Server,可接受的最大上限是80-85%
        合理使用的范围在60%至70%。
        2 Windows资源监控中,如果System\Processor Queue Length大于2,而处理器利用率(Processor Time)一直很低,则存在着处理器阻塞。

    CPU资源成为系统性能的瓶颈的征兆:   
         很慢的响应时间(slow response time)
         CPU空闲时间为零(zero percent idle CPU)
         过高的用户占用CPU时间(high percent user CPU)
         过高的系统占用CPU时间(high percent system CPU)
        长时间的有很长的运行进程队列(large run queue size sustained over time)

    磁盘I/O:
        1 UNIX资源监控(Windows操作系统同理)中指标磁盘交换率(Disk rate),如果该参数值一直很高,表明I/O有问题。可考虑更换更快的硬盘系统。
        2 Windows资源监控中,如果 Disk Time和Avg.Disk Queue Length的值很高,而Page Reads/sec页面读取操作速率很低,则可能存在磁盘瓶径。

    I/O资源成为系统性能的瓶颈的征兆 :
         过高的磁盘利用率(high disk utilization)
        太长的磁盘等待队列(large disk queue length)
        等待磁盘I/O的时间所占的百分率太高(large percentage of time waiting for disk I/O)
        太高的物理I/O速率:large physical I/O rate(not sufficient in itself)
        过低的缓存命中率(low buffer cache hit ratio(not sufficient in itself))
        太长的运行进程队列,但CPU却空闲(large run queue with idle CPU)

    4.数据库服务器:
    SQL Server数据库:
        1 SQLServer资源监控中指标缓存点击率(Cache Hit Ratio),该值越高越好。如果持续低于80%,应考虑增加内存。
        2 如果Full Scans/sec(全表扫描/秒)计数器显示的值比1或2高,则应分析你的查询以确定是否确实需要全表扫描,以及SQL查询是否可以被优化。
        3 Number of Deadlocks/sec(死锁的数量/秒):死锁对应用程序的可伸缩性非常有害,并且会导致恶劣的用户体验。该计数器的值必须为0。
       4 Lock Requests/sec(锁请求/秒),通过优化查询来减少读取次数,可以减少该计数器的值。

    Oracle数据库:
      1 如果自由内存接近于0而且库快存或数据字典快存的命中率小于0.90,那么需要增加SHARED_POOL_SIZE的大小。
        快存(共享SQL区)和数据字典快存的命中率:
       select(sum(pins-reloads))/sum(pins) from v$librarycache;
        select(sum(gets-getmisses))/sum(gets) from v$rowcache;
        自由内存:    select * from v$sgastat where name=’free memory’;
    2 如果数据的缓存命中率小于0.90,那么需要加大DB_BLOCK_BUFFERS参数的值(单位:块)。
      缓冲区高速缓存命中率:
        select name,value from v$sysstat where name in ('db block gets’,
        'consistent gets','physical reads') ;
       
        Hit Ratio = 1-(physical reads / ( db block gets + consistent gets))
    3 如果日志缓冲区申请的值较大,则应加大LOG_BUFFER参数的值。
        日志缓冲区的申请情况 :
         select name,value from v$sysstat where name = 'redo log space requests' ;
    4 如果内存排序命中率小于0.95,则应加大SORT_AREA_SIZE以避免磁盘排序 。
       内存排序命中率 :
         select round((100*b.value)/decode((a.value+b.value), 0, 1, (a.value+b.value)), 2)from v$sysstat a, v$sysstat b where a.name='sorts (disk)' and b.name='sorts (memory)'
       
        注:上述SQL Server和Oracle数据库分析,只是一些简单、基本的分析,特别是Oracle数据库的分析和优化,是一门专门的技术,进一步的分析可查相关资料。

    说明:
        以上只是个人的体会和部分资料的整理,并不代表专家之言。算抛砖引玉,有不同看法和更深入的分析的,希望大家勇要发言,以推动我们国内的性能测试工作。
  • 基于C/S结构的应用程序的性能测试

    2008-09-30 16:53:15

    虽然B/S结构愈来愈成为流行模式,但基于C/S结构的应用程序还广泛地应用于各种行业。 对于某些应用软件,其承受大用户量并发访问的能力常常是应用者重点考虑的一个方面。最好 的方法是用测试工具来模拟多个客户端同时访问服务器,并使用性能监测工具获得关于服务器、数据库等用户关心的性能指标。中国软件评测中心在多年的测试历程中,使用过多种性能测试工具,而对于C/S结构的应用程序,也总结了不少性能测试经验和方法。下面以中国软件评测中心经常用到的一种压力测试工具QALoad为例,说明这类性能测试需要注意的地方。

      1、首先分析压力测试中最容易出现瓶颈的地方,从而有目的地调整测试策略或测试环境,使压力测试结果真实地反映出软件的性能。例如,服务器的硬件限制、数据库的访问性能设置等常常会成为制约软件性能的重要因素,但这些因素显然不是用户最关心的,我们在测试之前就要通过一些设置把这些因素的影响调至最低。

      2、测试脚本至关重要。对于某些应用,如ADO、ODBC等等,QALoad可以录制/回放脚本,这给测试工作带来极大的便利,但用这样采集来的脚本直接作为压力测试的脚本往往会导致错误的结果。我们需要对原始的脚本进行修改,根据应用程序的实际情况和用户可能的操作情况调整脚本的结构,从而使脚本更符合实际情况。比如,我们录制一个用户登录、操作和注销的过程,实际情况是多数用户只登录一次,然后进行多次操作,这时我们只需在脚本中把登录和注销部分转至循环(即脚本中的Transaction部分)外即可。

      3、选用不同的加载策略可以反映不同状况下的性能。QALoad可采用的策略有:

      (1)并发用户数和每个模拟用户运行的事务数都为固定值;

      (2)并发用户按固定的时间间隔递增,每个模拟用户数运行的事务数不限;

      (3)以类似于批处理的方式顺序运行不同并发数的模拟用户,每个模拟用户运行的事务数 固定;

      (4)并发用户数固定,运行事务数不限,在一定的时间范围内持续运行脚本,然后手动停止;

      (5)不同模拟用户运行不同的脚本,模拟真实的访问情况。 另外,QALoad还提供设置数据变量和数据池,设置操作之间的间歇时间等功能,我们在运行脚本时可以充分利用这些策略和功能。

      4、寻求多种性能指标的获取方法。由QALoad本身提供的性能指标是每个“检查点”的响应时间,这些响应时间可以通过统计分析以获得更直观的结果,如平均响应时间、响应时间方差等等,但这些远远不能满足我们压力测试的需要。对于基于Windows系列平台的应用,QALoad可以添加Windows服务捕获的性能指标,前提是在服务器上安装QALoad的Agent组件并启动服务器上的SNMP等服务。对于如UNIX的其他平台,我们可以借助专用性能监测工具,如MAX、 ECOTool,以获取更有价值的性能数据。

      大多数性能测试,特别是基于C/S结构的应用软件的性能测试只有借助于测试工具才能完 成,另一方面,也需要测试工程师灵活的运用才能让测试工具充分发挥作用

1211/71234567>
Open Toolbar