分享
 
 
 

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

王朝other·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

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

刘彦清·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类似的场合中,这一方案并非总是可行的或理想的,然而,幸运的是,在设计类时可以采用一些技术,既能使用小一些的对象又不会遇到使用太多的小对象所引起的问题。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有