Java 优化 代码优化 介绍网站

Think in java 后面的附录章节 《性能》

D . 1 基本方法
只有正确和完整地检测了程序后,再可着手解决性能方面的问题:
(1) 在现实环境中检测程序的性能。若符合要求,则目标达到。若不符合,则转到下一步。
(2) 寻找最致命的性能瓶颈。这也许要求一定的技巧,但所有努力都不会白费。如简单地猜测瓶颈所在,并
试图进行优化,那么可能是白花时间。
(3) 运用本附录介绍的提速技术,然后返回步骤1。
为使努力不至白费,瓶颈的定位是至关重要的一环。Donald Knuth[9]曾改进过一个程序,那个程序把50%
的时间都花在约4%的代码量上。在仅一个工作小时里,他修改了几行代码,使程序的执行速度倍增。此
时,若将时间继续投入到剩余代码的修改上,那么只会得不偿失。Knuth 在编程界有一句名言:“过早的优
化是一切麻烦的根源”(Premature optimization is the root of all evil)。最明智的做法是抑制过早
优化的冲动,因为那样做可能遗漏多种有用的编程技术,造成代码更难理解和操控,并需更大的精力进行维
护。

D . 2 . 4 性能评测的技巧
由于评测时要用到系统时钟,所以当时不要运行其他任何进程或应用程序,以免影响测试结果。
如对自己的程序进行了修改,并试图(至少在开发平台上)改善它的性能,那么在修改前后应分别测
试一下代码的执行时间。
尽量在完全一致的环境中进行每一次时间测试。
如果可能,应设计一个不依赖任何用户输入的测试,避免用户的不同反应导致结果出现误差。


为进行客观的分析,最好明确掌握各种运算的执行时间。这样一来,得到的结果可独立于当前使用的计算

机——通过除以花在本地赋值上的时间,最后得到的就是“标准时间”。
运算 示例 标准时间
本地赋值 i=n; 1.0
实例赋值 this.i=n; 1.2
int 增值 i++; 1.5
byte 增值 b++; 2.0
short 增值 s++; 2.0
float 增值 f++; 2.0
double 增值 d++; 2.0
空循环 while(true) n++; 2.0
三元表达式 (x<0) ?-x : x 2.2
算术调用 Math.abs(x); 2.5
数组赋值 a[0] = n; 2.7
long 增值 l++; 3.5
方法调用 funct(); 5.9
throw 或catch 异常 try{ throw e; }或catch(e){} 320
同步方法调用 synchMehod(); 570
新建对象 new Object(); 980
新建数组 new int[10]; 3100


1. 常规修改
下面是加快Java 程序关键部分执行速度的一些常规操作建议(注意对比修改前后的测试结果)。
将... 修改成... 理由
接口 抽象类(只需一个父时) 接口的多个继承会妨碍性能的优化
非本地或数组循环变量 本地循环变量 根据前表的耗时比较,一次实例整数赋值的时间是本地整数赋值时间
的1.2 倍,但数组赋值的时间是本地整数赋值的2.7 倍
链接列表(固定尺寸) 保存丢弃的链接项目,或将列表替换成一个循环数组(大致知道尺寸) 每新建一个
对象,都相当于本地赋值980 次。


D . 3 . 3 特殊情况
■字串的开销:字串连接运算符+看似简单,但实际需要消耗大量系统资源。编译器可高效地连接字串,但变
量字串却要求可观的处理器时间。例如,假设s 和t 是字串变量:
System.out.println("heading" + s + "trailer" + t);
上述语句要求新建一个StringBuffer(字串缓冲),追加自变量,然后用toString()将结果转换回一个字
串。因此,无论磁盘空间还是处理器时间,都会受到严重消耗。若准备追加多个字串,则可考虑直接使用一
个字串缓冲——特别是能在一个循环里重复利用它的时候。通过在每次循环里禁止新建一个字串缓冲,可节
省980 单位的对象创建时间(如前所述)。利用substring()以及其他字串方法,可进一步地改善性能。如
果可行,字符数组的速度甚至能够更快。也要注意由于同步的关系,所以StringTokenizer 会造成较大的开
销。
■同步:在JDK 解释器中,调用同步方法通常会比调用不同步方法慢10 倍。经JIT 编译器处理后,这一性能
上的差距提升到50 到100 倍(注意前表总结的时间显示出要慢97 倍)。所以要尽可能避免使用同步方法—
—若不能避免,方法的同步也要比代码块的同步稍快一些。
■重复利用对象:要花很长的时间来新建一个对象(根据前表总结的时间,对象的新建时间是赋值时间的
980 倍,而新建一个小数组的时间是赋值时间的3100 倍)。因此,最明智的做法是保存和更新老对象的字
段,而不是创建一个新对象。例如,不要在自己的paint()方法中新建一个Font 对象。相反,应将其声明成
实例对象,再初始化一次。在这以后,可在paint()里需要的时候随时进行更新。参见Bentley 编著的《编
程拾贝》,p.81[15]。
■异常:只有在不正常的情况下,才应放弃异常处理模块。什么才叫“不正常”呢?这通常是指程序遇到了
问题,而这一般是不愿见到的,所以性能不再成为优先考虑的目标。进行优化时,将小的“try-catch”块合
并到一起。由于这些块将代码分割成小的、各自独立的片断,所以会妨碍编译器进行优化。另一方面,若过
份热衷于删除异常处理模块,也可能造成代码健壮程度的下降。
■散列处理:首先,Java 1.0 和1.1 的标准“散列表”(Hashtable)类需要造型以及特别消耗系统资源的
同步处理(570 单位的赋值时间)。其次,早期的JDK 库不能自动决定最佳的表格尺寸。最后,散列函数应
针对实际使用项(Key)的特征设计。考虑到所有这些原因,我们可特别设计一个散列类,令其与特定的应用
程序配合,从而改善常规散列表的性能。注意Java 1.2 集合库的散列映射(HashMap)具有更大的灵活性,
而且不会自动同步。
■方法内嵌:只有在方法属于final(最终)、private(专用)或static(静态)的情况下,Java 编译器
才能内嵌这个方法。而且某些情况下,还要求它绝对不可以有局部变量。若代码花大量时间调用一个不含上
述任何属性的方法,那么请考虑为其编写一个“final”版本。
■I/O:应尽可能使用缓冲。否则,最终也许就是一次仅输入/输出一个字节的恶果。注意JDK 1.0 的I/O 类
采用了大量同步措施,所以若使用象readFully()这样的一个“大批量”调用,然后由自己解释数据,就可
获得更佳的性能。也要注意Java 1.1 的“reader”和“writer”类已针对性能进行了优化。
■造型和实例:造型会耗去2 到200 个单位的赋值时间。开销更大的甚至要求上溯继承(遗传)结构。其他


■使用API 类:尽量使用来自Java API 的类,因为它们本身已针对机器的性能进行了优化。这是用Java 难
于达到的。比如在复制任意长度的一个数组时,arraryCopy()比使用循环的速度快得多。
■替换API 类:有些时候,API 类提供了比我们希望更多的功能,相应的执行时间也会增加。因此,可定做
特别的版本,让它做更少的事情,但可更快地运行。例如,假定一个应用程序需要一个容器来保存大量数
组。为加快执行速度,可将原来的Vector(矢量)替换成更快的动态对象数组。
1. 其他建议
■将重复的常数计算移至关键循环之外——比如计算固定长度缓冲区的buffer.length。
■static final(静态最终)常数有助于编译器优化程序。
■实现固定长度的循环。
■使用javac 的优化选项:-O。它通过内嵌static,final 以及private 方法,从而优化编译过的代码。注
意类的长度可能会增加(只对JDK 1.1 而言——更早的版本也许不能执行字节查证)。新型的“Just-intime”(
JIT)编译器会动态加速代码。


D . 4 参考资源
D . 4 . 1 性能工具
[1] 运行于Pentium Pro 200,Netscape 3.0,JDK 1.1.4 的MicroBenchmark(参见下面的参考资源[5])
[2] Sun 的Java 文档页——JDK Java 解释器主题:
http://java.sun.com/products/JDK/tools/win32/java.html
[3] Vladimir Bulatov 的HyperProf
http://www.physics.orst.edu/~bulatov/HyperProf
[4] Greg White 的ProfileViewer
http://www.inetmi.com/~gwhi/ProfileViewer/ProfileViewer.html
D . 4 . 2 W e b 站点
[5] 对于Java 代码的优化主题,最出色的在线参考资源是Jonathan Hardwick 的“Java Optimization”网
站:
http://www.cs.cmu.edu/~jch/java/optimization.html
“Java 优化工具”主页:
http://www.cs.cmu.edu/~jch/java/tools.html
以及“Java Microbenchmarks”(有一个45 秒钟的评测过程):
http://www.cs.cmu.edu/~jch/java/benchmarks.html
D . 4 . 3 文章
[6] “Make Java fast:Optimize! How to get the greatest performanceout of your code through lowlevel
optimizations in Java”(让Java 更快:优化!如何通过在Java 中的低级优化,使代码发挥最出色
的性能)。作者:Doug Bell。网址:
http://www.javaworld.com/javaworld/jw-04-1997/jw-04-optimize.html
(含一个全面的性能评测程序片,有详尽注释)
[7] “Java Optimization Resources ”(Java 优化资源)
http://www.cs.cmu.edu/~jch/java/resources.html
[8] “Optimizing Java for Speed”(优化Java,提高速度):
http://www.cs.cmu.edu/~jch/java/speed.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值