软件的性能设计(二) 临时对象对软件性能的影响

原创 2001年05月24日 15:08:00

                  软件的性能设计(二) 临时对象对软件性能的影响
    刘彦清·yesky

   临时对象的存在时间一般都比较短暂,除了作为其他数据的容器外,没有其他什么用途,开发人员一般用它向方法传递数据或从方法中返回数据。文章的第一部分探讨了创建临时对象是如何影响程序性能的,并表明恰当的类的接口设计可以有效地减少临时对象的创建。通过避免设计这样的接口,就可以减少临时对象的创建,降低对程序性能的影响程度。在本篇文章中,我将讨论过多地创建临时对象的问题并在后面的文章中提供一些成熟的技术来避免过多地创建临时对象。

  仅仅对String说NO?

  说到创建临时对象,String类是最大的"罪魁祸手"。为了说明这一点,我在这篇文章的第一部分中开发了一个表达式匹配类的例子,并演示了一个看起来颇为正常的接口是如何因为创建了临时对象而比一个具有较好接口的类似的类运行速度慢数倍的。下面是最初的和性能较好的类的接口:

  BadRegExpMatcher

  public class BadRegExpMatcher {

   public BadRegExpMatcher(String regExp);

   /** 把输入文本与特定的表达式进行匹配,如果匹配则返回匹配的文本,否则返回空字符 */

   public String match(String inputText);

  }

  BetterRegExpMatcher

  class BetterRegExpMatcher {

   public BetterRegExpMatcher(...);

   /** 向匹配子程序提供多种格式的输入━━String、字符数组和字符数组的子集。如果不匹配则返回-1,如果匹配,则返回匹配开始处的偏移量 */

   public int match(String inputText);

   public int match(char[] inputText);


   public int match(char[] inputText, int offset, int length);

   /** 如果匹配,则返回匹配的长度,调用程序可以从返回的匹配开始处偏移量和长度重新构造匹配的文本 */

   public int getMatchLength();

   /** 如果调用程序需要,这个例程可以很方便地构造出匹配字符串 */

   public String getMatchText();

  }

  大量使用BadRegExpMatcher的程序要比使用BetterRegExpMatcher的程序运行速度慢一些。第一,调用程序必须创建String对象向match()传递参数,match()也必须创建一个String对象向调用程序返回匹配的文本。每次调用时都会创建二个对象,这听起来也许没有什么大问题,但如果频繁地调用match(),创建这二个对象对性能产生的影响就大了。使用BadRegExpMatcher的程序的性能问题并不源于其编码而源于其接口,象这样设计的接口,临时对象的创建是不可避免的。

  BetterRegExpMatcher用比较简单的数据类型(整型、字符数组)取代了在match()中使用的String对象,从而无需在调用程序和match()之间通过中间对象传递数据。

  由于在设计阶段比在完成整个程序后再进行修改能够更好地避免程序性能方面的问题,因此应该在类的接口如何处理对象的创建这个问题上多花些时间。在RegExpMatcher中,其方法要求输入和返回String对象就可能对性能有潜在的影响,因为String类的对象是不可变的,因此对String类对象参数进行处理就会要求在每次调用时创建一个新的String对象。

  由于不可变性通常与额外的对象创建联系在一起━━这大部分原因都要"归功"于其不可变性,许多编程人员就断定不可变的对象一定会影响程序的性能。其实真实的情况要复杂得多,实际上,不可变性有时还能够提升程序的性能,可变的对象也能够引起程序性能的下降,可变性对程序性能的影响取决于其使用方式。

  程序会经常对文本字符串进行操作和修改━━不可改变性确实是一个麻烦。在每次对String进行操作时━━例如查找或选择一个前缀或子串,把它转换为大写或小写,或者将二个字符串合并成一个新的字符串时,就必须创建一个新的String类对象。

  另一方面,我们可以自由地共享一个不可变对象的地址而无需担心对象会被改变,此时,不可变对象在性能上就比可变对象要好许多。
可变对象也存在临时对象问题

  在RegExpMatcher中,当一个方法返回的数据类型为String类时,就有必要创建一个新的String类对象。在BadRegExpMatcher中存在的问题之一是match()返回的是一个对象而不是一个简单类型的数据━━因为一个方法返回一个对象,并不意味着一定会创建一个新的对象。考虑一下Point和Rectangle等java.awt中的几何类,一个Rectangle只不过是由四个整数━━左上角点的X、Y坐标以及宽度和高度组成的,AWT组件类存储了组件的位置并通过getBounds()方法将它作为一个Rectangle类对象返回:

  public class Component {
   ...
  public Rectangle getBounds();
  }

  在上面的例子中,getBounds()方法仅仅起一个辅助性作用,它只是声明一些组件内部的有关信息。getBounds()真的必须创建它返回的Rectangle对象吗?也许是这样的吧,我们来看一下getBounds()的编码:

  public class Component {
   ...
  protected Rectangle myBounds;

  public Rectangle getBounds() { return myBounds; }
  }

  当有程序调用上面例子中的getBounds()时,并不会创建新的对象,因为组件已经知道它的位置,因此getBounds()是比较高效的。然而,Rectangle的可变性还引起了其他问题,当一个调用它的程序执行下面的代码时会出现什么样的情况呢?

  Rectangle r = component.getBounds();
   ...
   r.height *= 2;

  因为Rectangle具有可变性,上面的代码将引起组件的改变,对于象AWT这样的GUI工具包而言,这将是灾难性的,因为当一个组件变化时,需要重新刷新屏幕,同时还需要通知事件监视程序。因此上面的Component.getBounds()的运行是相当危险的,下面所示的方式才是比较安全的:

  public Rectangle getBounds() {
   return new Rectangle(myBounds.x, myBounds.y,
   myBounds.height, myBounds.width);
  }

  但是,就象RegExpMatcher那样,每次调用getBounds()都会创建一个新的对象,下面的代码将会创建四个临时对象:

  int x = component.getBounds().x;
  int y = component.getBounds().y;
  int h = component.getBounds().height;
  int w = component.getBounds().width;

  对于String类而言,创建对象是必要的,因为String是不可变的。但是在这个例子中,创建临时对象似乎也是必需的,因为Rectangle具有可变性,我们可以通过不在接口中使用任何对象来避免象String引起的那样的问题。尽管在与RegExpMatcher类似的场合中,这一方案并非总是可行的或理想的,然而,幸运的是,在设计类时可以采用一些技术,既能使用小一些的对象又不会遇到使用太多的小对象所引起的问题。

架构设计中影响性能的因素及解决方案

性能(performance)设计非常重要,对于服务器端实时交易系统来说系统性能的重要性不言而喻,对客户端软件来说性能好的软件也会获得良好的用户体验,从而给用户留下高质量软件的良好印象。因此在进行架构...
  • bzhxuexi
  • bzhxuexi
  • 2015年06月15日 09:54
  • 1095

软件架构设计之一:系统性能评价

一、本章要点 1)性能计算(响应时间、吞吐量、TAT) 2)性能设计(系统调整、Amdahl解决方案、响应特性、负载均衡)。 3)性能指标(SPEC-Int、SPEC-Fp、TPC、Gibsonmix...
  • slowwind2007_lishu
  • slowwind2007_lishu
  • 2013年07月18日 22:13
  • 1711

软件性能测试完整指南

译文 | 软件性能测试完整指南 作者 | Angela Stringfellow 来源 | DZone 原文 | https://dzone.com/articles/a-com...
  • abdstime
  • abdstime
  • 2017年05月26日 13:50
  • 557

软件性能测试基本概念和流程

1.1    软件性能的定义 通常来说,性能首先是一种指标,表明软件系统或构件对其即时性要求的符合程度;其次是软件产品的的一种特性,可以用时间来进行衡量。性能的及时性用响应时间或吞吐量来衡量...
  • jiangbqing
  • jiangbqing
  • 2017年01月12日 11:53
  • 919

软件性能测试的几种方法

首先我们来看看什么是软件性能?         软件的性能是软件的一种非功能特性,它关注的不是软件是否能够完成特定的功能,而是在完成该功能时展示出来的及时性。 表明了软件系统对时间及时性及资源经...
  • youngyunq
  • youngyunq
  • 2015年11月27日 22:27
  • 5740

软件性能测试知识点总结

第一章 软件性能概述 1.1软件性能基础 1.1.1软件性能的概念 软件性能是与软件功能相对应的一种非常重要的非功能特性,表明了软件系统对时间及时性与资源经济性的要求。对于一个软件系统,运行时执...
  • u011484013
  • u011484013
  • 2016年04月17日 19:59
  • 2101

浅谈软件性能测试中关键指标的监控与分析

浅谈软件性能测试中关键指标的监控与分析 一、软件性能测试需要监控哪些关键指标? 软件性能测试的目的主要有以下三点: Ø  评价系统当前性能,判断系统是否满足预期的性能需求。 Ø  寻找软件系统...
  • qq_21064841
  • qq_21064841
  • 2016年11月29日 15:00
  • 292

软件性能的简要概述 衡量指标 测试原则

软件的性能和功能最终都是(直接或间接的)来源于用户的需求 最原始的性能需求:在硬件资源一定的条件下,尽量少占硬件资源,软件的运行速度要足够快。 软件功能的关注点是:能够做什么 软件性能的关注点是...
  • yong_sun
  • yong_sun
  • 2013年03月09日 11:21
  • 2168

软件测试之性能测试

软件测试之性能测试:大促带来的灾难 性能测试是产品测试流程的必经之路,产品性能的好坏不但关系到产品的用户体验,对于像电子商务这一的应用来说,性能的好坏直接关系到客户的网站是否有好的用户忠诚度,从...
  • wuxiaobingandbob
  • wuxiaobingandbob
  • 2015年09月21日 08:53
  • 820

软件性能优化漫谈(一):软件性能测量与分析

所谓软件性能优化,就是指在不改变硬件的前提下,通过软件的等价变换获得更高的执行速度。在本系列文章中,将从软件性能测量与分析、性能优化方法和技术实践等方面,谈一谈软件性能优化的相关问题。...
  • jacks_sure
  • jacks_sure
  • 2016年11月23日 09:18
  • 502
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:软件的性能设计(二) 临时对象对软件性能的影响
举报原因:
原因补充:

(最多只允许输入30个字)