Java性能设计
作者:xiaoliu52013 日期:2007-10-08 10:19:42
很多程序员在一开始并不注重性能的设计,只有当系统交付运行时,才 发现问题并且开始解决这一问题,但往往这只能挽救一点点。性能的管理应该一开始 就被整合到设计和开发当中去。
最普遍的问题就是临时对象大量经常的创建,这为性能埋下隐患。
性能的问题来自很多原因,最容易解决的可能是:你选择了不好的算法来进行计算,如 用冒泡法来排序巨量数据,或者你每次使用数据时都要反复计算一次,这应该使用Cache。
你能很容易的使用工具(如Borland的Optimizeit)或压力测试发现这些问题, 一旦发现,就能够立即被纠正,但是很多Java的性能问题隐藏得更深,难于修改源码就能纠正, 如程序组件的接口设计。
现在我们倡导面向对象的组件可复用设计,无疑这样设计的优点是巨大的, 但是也要注意到对性能的影响。
一个java性能设计原则是,避免不必要的对象创建,对象的创建是非常耗时的, 所以你要避免不必要的临时或过多的对象创建,
String是程序中最主要创建的对象,因为String是不变的,如果String长度被修改 将导致String对象再次创建,所以对性能有所注意的一般人就是尽量回避使用String, 但是这几乎是不可能的。
接口参数设计
举例 MailBot:
MailBot邮件系统的有一个Header数据,它是character buffer,需要对这个character buffer 进行分析比较,那么你要做一个类Matcher,在这个类中你将Header数据读入然后配比, 一个不好的做法是:
public class BadRegExpMatcher {
public BadRegExpMatcher(String regExp);
/** Attempts to match the specified regular expression against the input text, returning the matched text if possible or null if not
*/
public String match(String inputText);
}
这个BadRegExpMatche要求入口参数是String ,那么如果MailBot要调用他,必须自己做一个 character buffer到String的转换:
BadRegExpMatcher dateMatcher = new BadRegExpMatcher(...);
while (...) { ...
//产生新的String
String headerLine = new String(myBuffer, thisHeaderStart, thisHeaderEnd-thisHeaderStart);
String result = dateMatcher.match(headerLine);
if (result == null) { ... }
}
很明显,这里这个由于接口不一致导致了多余的对象String headerline的创建,这是不能允许的, 应该将Matcher的接口设计成能够接纳character buffer,当然为通用性,也应该提供String的 接口参数:
class BetterRegExpMatcher {
public BetterRegExpMatcher(...);
/** 提供多个接口参数的match方法
Provide matchers for multiple formats of input -- String,
character array, and subset of character array. Return
-1 if no match was made; return offset of match start if
a match was made. */
public int match(String inputText);
public int match(char[] inputText);
public int match(char[] inputText, int offset, int length);
/** Get the next match against the input text, if any */
public int getNextMatch();
public int getMatchLength();
public String getMatchText();
}
很明显BetterRegExpMatcher的运行速度将比前面BadRegExpMatcher运行速度快。
因为在你已经写好代码的情况下,你比较难于更改一个类的接口参数,那就应该在写程序之前多 多考虑你这些接口参数的类型设定,最好有一个通盘的接口类型规定。
减少对象的创建
临时对象是那些有很短的生命周期,通常服务一些非十分有用的目标,程序员通常使用临时对象作为 数据混合包传送或者返回,为避免上述示例哪些转换接口对象的构造,你应该巧妙的避免创造这些临时 对象,以防止给你的程序留下性能的阴影。
上述示例说明性能问题在于String对象,但是String在对象创建中又是如此的普遍,String是不变的,一旦赋值,就不会变化,不少程序员 认为不变的东西总是会导致坏的性能,其实它并不是这么简单,实际上,性能好坏在于你如何使用这个东西。
对于经常需要变化的String,很明显使用Stringbuffer来代替。
举例:
看下面两种实现:
public class Component {
...
protected Rectangle myBounds;
public Rectangle getBounds() { return myBounds; }
}
和
public class Component {
public Rectangle getBounds() {
return new Rectangle(myBounds.x, myBounds.y, myBounds.height,
myBounds.width);
}
}
当使用Component分别对应有如下两种:
Rectangle r = component.getBounds();
...
r.height *= 2;
和
int x = component.getBounds().x;
int y = component.getBounds().y;
int h = component.getBounds().height;
int w = component.getBounds().width;
第一种使用方式缺点,r.height的使用已经脱离component,容易引起沟通上的误解,因为 Rectangle变化必须涉及component内容重新刷新,万一其它程序员不知道这个规则,修改 r.height(乘2),将不会去刷新component,
第二中方式是个提高,迫使componenet和其部件跟随在一起。但是带来问题是:创建了 四个临时对象。
改进办法是,在第一种的基础上,在Commponent中增加
public int getX() { return myBounds.x; }
public int getY() { return myBounds.y; }
public int getHeight() { return myBounds.height; }
public int getWidth() { return myBounds.width; }
这样调用变成:
int x = component.getX();
int y = component.getY();
int h = component.getHeight();
int w = component.getWidth();
两全其美了不是?
这就是减少创建对象技巧之一: 增加finer-grained辅助功能
第二种技巧是:Exploit mutability
上例还有一种实现方式:
public Rectangle getBounds(Rectangle returnVal) {
returnVal.x = myBounds.x;
returnVal.y = myBounds.y;
returnVal.height = myBounds.height;
returnVal.width = myBounds.width;
return returnVal;
}
多巧妙,把Rectangle作为参数传进来修改一下再送出去。
技巧3是 融合变和不变于一身。
总结上面一些例子,发现一个规律:临时对象产生是在这种情况下产生的: 不变的要转换成可变的。那么针对这个根本原因我们设计出各取所需的方案。
以下例说明:
Point是不变的,我们继承它,定义一个可变的子类。
public class Point {
protected int x, y;
public Point(int x, int y) { this.x = x; this.y = y; }
public final int getX() { return x; }
public final int getY() { return y; }
}
public class MutablePoint extends Point {
public final void setX(int x) { this.x = x; }
public final void setY(int y) { this.y = y; }
}
这样,可变的需求和不可变的需求各自满足,分别调用。
public class Shape {
private MutablePoint myLocation;
//返回可变的
public Shape(int x, int y) {
myLocation = new MutablePoint(x, y);
}
//返回不变的
public Point getLocation() { return (Point) myLocation; } }
远程接口
在分布式应用中,性能也是相当重要的,这里介绍如何通过检查class的接口 能简单预知分布式应用中的性能问题。
在分布式应用中,一个在这个系统中运行的对象能够调用另外一个系统的对象的方法,这是通过很多 内部机制来实现将远程对象貌似本地对象的,为了发现远程对象,你首先必须发现它,这是通过一种 名称目录服务机制,比如RMO的注册,JNDO和CORBA的名称服务。
当你通过目录服务得到一个远程的对象,你不是得到一个实际的指向,而是一个和远程行为一样的stub对象的 指向, 当你调用stub对象的一个方法时,这个得marshal这个方法参数:也就是转换成byte-stream,这类似 于序列化,这个stub对象通过网络将marshal后的参数发送给skeleton对象,后者负责unmarshal这些参数然后 调用真正实际的你要调用的远程方法,然后,这个方法返回一个值给skeleton,再逐个沿着刚才路线返回, 一个简单方法要做这么多工作啊。
很显然,远程方法调用要比本地方法调用来得耗时昂贵。
上面返回情况是是指返回原始型primitive,如果返回的是对象,怎么办?如果这个对象支持远程调用,它又会通过查询创造一个stub和skeleton对象,这又是耗时的;如果这个对象不支持远程调用,那么所有的对象的字段和任何涉及引用的对象都要被marshal,这也是 相当耗时的。
由此可见,一个不好的远程接口设计将完全扼杀程序的性能,为了避免网络开销,设计一次 远程调用返回多值总比多次调用,每次只返回一个值要好得多。
还有提防在不需要返回远程对象时,返回一个远程对象。不要传递很复杂不必要的对象给远程。
假设远程服务器有一个目录列表对象,每个目录项目中包含姓名 电话号码 和邮件地址等值, 下列程序:
public interface Directory extends Remote {
DirectoryEntry[] getEntries();
void addEntry(DirectoryEntry entry);
void removeEntry(DirectoryEntry entry);
}
public interface DirectoryEntry extends Remote {
String getName();
String getPhoneNumber();
String getEmailAddress();
}
这样设计导致结果是,当我需要一个姓名值时,首先要获得Directory 对象,再获得DirectoryEntry, 获得DirectoryEntry才能获得getName,这么来来回回,需要多少次网络开销啊。
public interface Directory extends Remote {
String[] getNames();
DirectoryEntry[] getEntries();
//加入这个方法
DirectoryEntry getEntryByName(String name);
void addEntry(DirectoryEntry entry);
void removeEntry(DirectoryEntry entry);
}
这样直接在Directory加上DirectoryEntry和getNames(),一次网络开销就全部解决。
当然这样的解决方案是完全建立在对分布式应用原理了解的基础上。
--------------转------------------
最普遍的问题就是临时对象大量经常的创建,这为性能埋下隐患。
性能的问题来自很多原因,最容易解决的可能是:你选择了不好的算法来进行计算,如 用冒泡法来排序巨量数据,或者你每次使用数据时都要反复计算一次,这应该使用Cache。
你能很容易的使用工具(如Borland的Optimizeit)或压力测试发现这些问题, 一旦发现,就能够立即被纠正,但是很多Java的性能问题隐藏得更深,难于修改源码就能纠正, 如程序组件的接口设计。
现在我们倡导面向对象的组件可复用设计,无疑这样设计的优点是巨大的, 但是也要注意到对性能的影响。
一个java性能设计原则是,避免不必要的对象创建,对象的创建是非常耗时的, 所以你要避免不必要的临时或过多的对象创建,
String是程序中最主要创建的对象,因为String是不变的,如果String长度被修改 将导致String对象再次创建,所以对性能有所注意的一般人就是尽量回避使用String, 但是这几乎是不可能的。
接口参数设计
举例 MailBot:
MailBot邮件系统的有一个Header数据,它是character buffer,需要对这个character buffer 进行分析比较,那么你要做一个类Matcher,在这个类中你将Header数据读入然后配比, 一个不好的做法是:
public class BadRegExpMatcher {
public BadRegExpMatcher(String regExp);
/** Attempts to match the specified regular expression against the input text, returning the matched text if possible or null if not
*/
public String match(String inputText);
}
这个BadRegExpMatche要求入口参数是String ,那么如果MailBot要调用他,必须自己做一个 character buffer到String的转换:
BadRegExpMatcher dateMatcher = new BadRegExpMatcher(...);
while (...) { ...
//产生新的String
String headerLine = new String(myBuffer, thisHeaderStart, thisHeaderEnd-thisHeaderStart);
String result = dateMatcher.match(headerLine);
if (result == null) { ... }
}
很明显,这里这个由于接口不一致导致了多余的对象String headerline的创建,这是不能允许的, 应该将Matcher的接口设计成能够接纳character buffer,当然为通用性,也应该提供String的 接口参数:
class BetterRegExpMatcher {
public BetterRegExpMatcher(...);
/** 提供多个接口参数的match方法
Provide matchers for multiple formats of input -- String,
character array, and subset of character array. Return
-1 if no match was made; return offset of match start if
a match was made. */
public int match(String inputText);
public int match(char[] inputText);
public int match(char[] inputText, int offset, int length);
/** Get the next match against the input text, if any */
public int getNextMatch();
public int getMatchLength();
public String getMatchText();
}
很明显BetterRegExpMatcher的运行速度将比前面BadRegExpMatcher运行速度快。
因为在你已经写好代码的情况下,你比较难于更改一个类的接口参数,那就应该在写程序之前多 多考虑你这些接口参数的类型设定,最好有一个通盘的接口类型规定。
减少对象的创建
临时对象是那些有很短的生命周期,通常服务一些非十分有用的目标,程序员通常使用临时对象作为 数据混合包传送或者返回,为避免上述示例哪些转换接口对象的构造,你应该巧妙的避免创造这些临时 对象,以防止给你的程序留下性能的阴影。
上述示例说明性能问题在于String对象,但是String在对象创建中又是如此的普遍,String是不变的,一旦赋值,就不会变化,不少程序员 认为不变的东西总是会导致坏的性能,其实它并不是这么简单,实际上,性能好坏在于你如何使用这个东西。
对于经常需要变化的String,很明显使用Stringbuffer来代替。
举例:
看下面两种实现:
public class Component {
...
protected Rectangle myBounds;
public Rectangle getBounds() { return myBounds; }
}
和
public class Component {
public Rectangle getBounds() {
return new Rectangle(myBounds.x, myBounds.y, myBounds.height,
myBounds.width);
}
}
当使用Component分别对应有如下两种:
Rectangle r = component.getBounds();
...
r.height *= 2;
和
int x = component.getBounds().x;
int y = component.getBounds().y;
int h = component.getBounds().height;
int w = component.getBounds().width;
第一种使用方式缺点,r.height的使用已经脱离component,容易引起沟通上的误解,因为 Rectangle变化必须涉及component内容重新刷新,万一其它程序员不知道这个规则,修改 r.height(乘2),将不会去刷新component,
第二中方式是个提高,迫使componenet和其部件跟随在一起。但是带来问题是:创建了 四个临时对象。
改进办法是,在第一种的基础上,在Commponent中增加
public int getX() { return myBounds.x; }
public int getY() { return myBounds.y; }
public int getHeight() { return myBounds.height; }
public int getWidth() { return myBounds.width; }
这样调用变成:
int x = component.getX();
int y = component.getY();
int h = component.getHeight();
int w = component.getWidth();
两全其美了不是?
这就是减少创建对象技巧之一: 增加finer-grained辅助功能
第二种技巧是:Exploit mutability
上例还有一种实现方式:
public Rectangle getBounds(Rectangle returnVal) {
returnVal.x = myBounds.x;
returnVal.y = myBounds.y;
returnVal.height = myBounds.height;
returnVal.width = myBounds.width;
return returnVal;
}
多巧妙,把Rectangle作为参数传进来修改一下再送出去。
技巧3是 融合变和不变于一身。
总结上面一些例子,发现一个规律:临时对象产生是在这种情况下产生的: 不变的要转换成可变的。那么针对这个根本原因我们设计出各取所需的方案。
以下例说明:
Point是不变的,我们继承它,定义一个可变的子类。
public class Point {
protected int x, y;
public Point(int x, int y) { this.x = x; this.y = y; }
public final int getX() { return x; }
public final int getY() { return y; }
}
public class MutablePoint extends Point {
public final void setX(int x) { this.x = x; }
public final void setY(int y) { this.y = y; }
}
这样,可变的需求和不可变的需求各自满足,分别调用。
public class Shape {
private MutablePoint myLocation;
//返回可变的
public Shape(int x, int y) {
myLocation = new MutablePoint(x, y);
}
//返回不变的
public Point getLocation() { return (Point) myLocation; } }
远程接口
在分布式应用中,性能也是相当重要的,这里介绍如何通过检查class的接口 能简单预知分布式应用中的性能问题。
在分布式应用中,一个在这个系统中运行的对象能够调用另外一个系统的对象的方法,这是通过很多 内部机制来实现将远程对象貌似本地对象的,为了发现远程对象,你首先必须发现它,这是通过一种 名称目录服务机制,比如RMO的注册,JNDO和CORBA的名称服务。
当你通过目录服务得到一个远程的对象,你不是得到一个实际的指向,而是一个和远程行为一样的stub对象的 指向, 当你调用stub对象的一个方法时,这个得marshal这个方法参数:也就是转换成byte-stream,这类似 于序列化,这个stub对象通过网络将marshal后的参数发送给skeleton对象,后者负责unmarshal这些参数然后 调用真正实际的你要调用的远程方法,然后,这个方法返回一个值给skeleton,再逐个沿着刚才路线返回, 一个简单方法要做这么多工作啊。
很显然,远程方法调用要比本地方法调用来得耗时昂贵。
上面返回情况是是指返回原始型primitive,如果返回的是对象,怎么办?如果这个对象支持远程调用,它又会通过查询创造一个stub和skeleton对象,这又是耗时的;如果这个对象不支持远程调用,那么所有的对象的字段和任何涉及引用的对象都要被marshal,这也是 相当耗时的。
由此可见,一个不好的远程接口设计将完全扼杀程序的性能,为了避免网络开销,设计一次 远程调用返回多值总比多次调用,每次只返回一个值要好得多。
还有提防在不需要返回远程对象时,返回一个远程对象。不要传递很复杂不必要的对象给远程。
假设远程服务器有一个目录列表对象,每个目录项目中包含姓名 电话号码 和邮件地址等值, 下列程序:
public interface Directory extends Remote {
DirectoryEntry[] getEntries();
void addEntry(DirectoryEntry entry);
void removeEntry(DirectoryEntry entry);
}
public interface DirectoryEntry extends Remote {
String getName();
String getPhoneNumber();
String getEmailAddress();
}
这样设计导致结果是,当我需要一个姓名值时,首先要获得Directory 对象,再获得DirectoryEntry, 获得DirectoryEntry才能获得getName,这么来来回回,需要多少次网络开销啊。
public interface Directory extends Remote {
String[] getNames();
DirectoryEntry[] getEntries();
//加入这个方法
DirectoryEntry getEntryByName(String name);
void addEntry(DirectoryEntry entry);
void removeEntry(DirectoryEntry entry);
}
这样直接在Directory加上DirectoryEntry和getNames(),一次网络开销就全部解决。
当然这样的解决方案是完全建立在对分布式应用原理了解的基础上。
--------------转------------------
平均得分
(0 次评分)
评论: 9 | 查看次数: 959
- 共有 9 条评论
- 共有 9 条评论
发表评论
订阅
上一篇
|

文章来自:
标签: 





李小龙生于wholesale nike美国三藩市,他的童年和wholesale jordan shoes 少年是在香港度过的。jordan shoes wholesale 李小龙幼时身体非常瘦 wholesale air jordan 弱。他父亲为了儿子
air jordan wholesale 李小龙在wholesale gucci shoes西雅图的生活相当gucci shoes wholesale艰苦,进人大学wholesale air force one就读以后,他除air force one wholesale了学习外wholesale air force ones,把精力都放cheap jordan shoes在研习武术上。他在学校里组织了一支“中国功夫队”,经常在校园里air force ones wholesale进行训练和表演
父亲为了儿子wholesale jordan shoes1971年
窃听器
手机监听器
监听器
手机窃听器
窃听器
手机监听器
监听器
手机窃听器
窃听器
手机监听器
监听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
手机窃听器│窃听器
You can also send any useless greens you find with your warriorwow gold to your alt.but it's easier if you can also make your own.
Speak tobuy the book Expert Fishing: The Bass and You.Once your up to 175 cooking, go to Shadowprey Village in Desolace.
You can also send any useless greens you find with your warriorwow gold to your alt.but it's easier if you can also make your own.
free online games
play war games
free online war games
online games
精油
论文发表
上海翻译公司
上海翻译
英语培训
英语口语
神经性皮炎
皮炎
湿疹
荨麻疹
慢性荨麻疹
藏獒
液压缸
油缸
防腐管道
破碎机
北京旅游
北京旅行社
条码机
条码打印机
条形码打印机
阴茎增大
伟哥
发酵罐
冰淇淋
加盟店
冷饮店
冰淇淋机
冰淇淋粉
冰激凌
大豆床上用品
保健内衣
羊绒内衣
大豆纤维面料
团购礼品
移民
投资移民
商业移民
技术移民
美国移民
澳洲移民
德国移民
英国移民
加拿大移民
热电偶插头
测温线
热电阻
硅碳棒
除湿机
抽湿机
工业除湿机
空气净化器
空气净化机
men spa beijing
men massage beijing
pearl jewelry
Beijing Tour
china Tour
beijing Tour
china Tour
beijing Tour
China Necklace Wholesale
China Bracelet Wholesale
China Ring wholesale
China gemstone beads wholesale
China Jewelry Accessories wholesale
China Semiprecious beads wholesale
replica handbag
replica tiffany
replica watches
replica jewelry
replica tiffany
replica handbag
louis vuitton handbag
gucci handbag
chanel handbag
louis vuitton replica
chanel replica
gucci replica
Chinese language
Chinese learn
learning Chinese
learn mandarin
ecosway
gasifier
coal gas
coal gasification
pro dj cases
beijing tour
beijing tours
beijing travel
beijing tours
china tour
beijing
china tours
china travel
beijing china
china beijing
beijing hotel
beijing hotels
China Flights
l2 adena
wow gold
world of warcraft gold
lotro gold
lord of the rings online gold