八宝书库 > 文学其他电子书 > Java编程思想第4版[中文版](PDF格式) >

第176部分

Java编程思想第4版[中文版](PDF格式)-第176部分

小说: Java编程思想第4版[中文版](PDF格式) 字数: 每页4000字

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




销。  

■同步:在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 个单位的赋值时间。开销更大的甚至要求上溯继承(遗传)结构。其他 



                                                                     681 


…………………………………………………………Page 683……………………………………………………………

高代价的操作会损失和恢复更低层结构的能力。  

■图形:利用剪切技术,减少在repaint()中的工作量;倍增缓冲区,提高接收速度;同时利用图形压缩技 

术,缩短下载时间。来自JavaWorld 的“Java Applets”以及来自 Sun 的“Performing Animation”是两个 

很好的教程。请记着使用最贴切的命令。例如,为根据一系列点画一个多边形,和drawLine()相比, 

drawPolygon()的速度要快得多。如必须画一条单像素粗细的直线,drawLine(x;y;x;y)的速度比 

fillRect(x;y;1;1)快。  

■使用API 类:尽量使用来自 Java API 的类,因为它们本身已针对机器的性能进行了优化。这是用Java 难 

于达到的。比如在复制任意长度的一个数组时,arraryCopy()比使用循环的速度快得多。  

■替换API 类:有些时候,API 类提供了比我们希望更多的功能,相应的执行时间也会增加。因此,可定做 

特别的版本,让它做更少的事情,但可更快地运行。例如,假定一个应用程序需要一个容器来保存大量数 

组。为加快执行速度,可将原来的 Vector (矢量)替换成更快的动态对象数组。  

  

1。 其他建议  

■将重复的常数计算移至关键循环之外——比如计算固定长度缓冲区的buffer。length 。  

■static final (静态最终)常数有助于编译器优化程序。  

■实现固定长度的循环。  

■使用javac 的优化选项:…O。它通过内嵌static,final 以及private 方法,从而优化编译过的代码。注 

意类的长度可能会增加(只对JDK 1。1 而言——更早的版本也许不能执行字节查证)。新型的“Just…in

time”(JIT)编译器会动态加速代码。  

■尽可能地将计数减至 0——这使用了一个特殊的JVM 字节码。  



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。/products/JDK/tools/win32/java。html  

'3' Vladimir Bulatov的HyperProf  

http://physics。orst。edu/~bulatov/HyperProf  

'4' Greg White 的ProfileViewer  

http://inetmi。/~gwhi/ProfileViewer/ProfileViewer。html  



D。4。2 Web 站点  



'5' 对于Java 代码的优化主题,最出色的在线参考资源是Jonathan Hardwick 的“Java Optimization”网 

站:  

http://cs。cmu。edu/~jch/java/optimization。html  

 “Java 优化工具”主页:  

http://cs。cmu。edu/~jch/java/tools。html  

以及“Java Microbenchmarks”(有一个45 秒钟的评测过程):  

http://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 low

level optimizations in Java”(让Java 更快:优化!如何通过在Java 中的低级优化,使代码发挥最出色 

的性能)。作者:Doug Bell。网址:  

http://javaworld。/javaworld/jw…04…1997/jw…04…optimize。html  

 (含一个全面的性能评测程序片,有详尽注释)  

'7'  “Java Optimization Resources ”(Java 优化资源)  

http://cs。cmu。edu/~jch/java/resources。html  

'8'  “Optimizing Java for Speed”(优化Java,提高速度):  

http://cs。cmu。edu/~jch/java/speed。html  



                                                                               682 


…………………………………………………………Page 684……………………………………………………………

'9'  “An Empirical Study of FORTRAN Programs”(FORTRAN 程序实战解析)。作者:Donald Knuth。 

1971 年出版。第 1卷,p。105…33,“软件——实践和练习”。  

'10'  “Building High…Performance Applications and Servers in Java:An Experiential Study”。作 

者:Jimmy Nguyen,Michael Fraenkel,RichardRedpath,Binh Q。 Nguyen 以及Sandeep K。 Singhal。IBM  

T。J。 Watson ResearchCenter;IBM Software Solutions。  

http://ibm。/java/education/javahipr。html  



D。4。4 Java 专业书籍  



'11'  《Advanced Java ,Idioms,Pitfalls ,Styles; and Programming Tips》。作者:Chris Laffra。 

Prentice Hall 1997 年出版(Java 1。0 )。第 11 章第20 小节。  



D。4。5  一般书籍  



'12'  《Data Structures and C Programs》(数据结构和C 程序)。作者:J。Van Wyk。Addison…Wesly  

1998 年出版。  

'13'  《Writing Efficient Programs》(编写有效的程序)。作者:Jon Bentley。Prentice Hall 1982 年 

出版。特别参考p。110 和p。145…151。  

'14'  《More Programming Pearls》(编程拾贝第二版)。作者:JonBentley。“Association for  

puting Machinery”,1998 年2 月。  

'15'  《Programming Pearls 》(编程拾贝)。作者:Jone Bentley。Addison…Wesley 1989 年出版。第2 部 

分强调了常规的性能改善问题。 '16'  《Code plete:A Practical Handbook of Software  

Construction》(完整代码索引:实用软件开发手册)。作者:Steve McConnell。Microsoft 出版社 1993 

年出版,第 9 章。  

'17'  《Object…Oriented System Development》(面向对象系统的开发)。作者:Champeaux,Lea 和 

Faure。第25 章。  

'18'  《The Art of Programming》(编程艺术)。作者:Donald Knuth。第1卷“基本算法第3 版”;第3 

卷“排序和搜索第 2 版”。Addison…Wesley 出版。这是有关程序算法的一本百科全书。  

'19'  《Algorithms in C:Fundammentals;Data Structures; Sorting;Searching》(C 算法:基础、数据结 

构、排序、搜索)第3 版。作者:RobertSedgewick。Addison…Wesley 1997 年出版。作者是Knuth 的学生。 

这是专门讨论几种语言的七个版本之一。对算法进行了深入浅出的解释。  



                                                                                      683 


…………………………………………………………Page 685……………………………………………………………

                 附录 E 关于垃圾收集的一些话  



  

 “很难相信Java 居然能和C++一样快,甚至还能更快一些。”  

据我自己的实践,这种说法确实成立。然而,我也发现许多关于速度的怀疑都来自一些早期的实现方式。由 

于这些方式并非特别有效,所以没有一个模型可供参考,不能解释Java 速度快的原因。  

我之所以想到速度,部分原因是由于C++模型。C++将自己的主要精力放在编译期间“静态”发生的所有事情 

上,所以程序的运行期版本非常短小和快速。C++也直接建立在C 模型的基础上(主要为了向后兼容),但有 

时仅仅由于它在C 中能按特定的方式工作,所以也是C++中最方便的一种方法。最重要的一种情况是C 和C++ 

对内存的管理方式,它是某些人觉得Java 速度肯定慢的重要依据:在Java 中,所有对象都必须在内存 

 “堆”里创建。  

而在C++中,对象是在堆栈中创建的。这样可达到更快的速度,因为当我们进入一个特定的作用域时,堆栈 

指针会向下移动一个单位,为那个作用域内创建的、以堆栈为基础的所有对象分配存储空间。而当我们离开 

作用域的时候(调用完毕所有局部构建器后),堆栈指针会向上移动一个单位。然而,在C++里创建“内存 

堆”(Heap )对象通常会慢得多,因为它建立在C 的内存堆基础上。这种内存堆实际是一个大的内存池,要 

求必须进行再循环(再生)。在C++里调用 delete 以后,释放的内存会在堆里留下一个洞,所以再调用new 

的时候,存储分配机制必须进行某种形式的搜索,使对象的存储与堆内任何现成的洞相配,否则就会很快用 

光堆的存储空间。之所以内存堆的分配会在C++里对性能造成如此重大的性能影响,对可用内存的搜索正是 

一个重要的原因。所以创建基于堆栈的对象要快得多。  

同样地,由于C++如此多的工作都在编译期间进行,所以必须考虑这方面的因素。但在 Java 的某些地方,事 

情的发生却要显得“动态”得多,它会改变模型。创建对象的时候,垃圾收集器的使用对于提高对象创建的 

速度产生了显著的影响。从表面上看,这种说法似乎有些奇怪——存储空间的释放会对存储空间的分配造成 

影响,但它正是JVM 采取的重要手段之一,这意味着在 Java 中为堆对象分配存储空间几乎能达到与C++中在 

堆栈里创建存储空间一样快的速度。  

可将C++的堆(以及更慢的 Java 堆)想象成一个庭院,每个对象都拥有自己的一块地皮。在以后的某个时 

间,这种“不动产”会被抛弃,而且必须再生。但在某些 JVM 里,Java 堆的工作方式却是颇有不同的。它更 

象一条传送带:每次分配了一个新对象后,都会朝前移动。这意味着对象存储空间的分配可以达到非常快的 

速度。“堆指针”简单地向前移至处女地,所以它与C++的堆栈分配方式几乎是完全相同的(当然,在数据 

记录上会多花一些开销,但要比搜索存储空间快多了)。  

现在,大家可能注意到了堆事实并非一条传送带。如按那种方式对待它,最终就要求进行大量的页交换(这 

对性能的发挥会产生巨大干扰),这样终究会用光内存,出现内存分页错误。所以这儿必须采取一个技巧, 

那就是著名的“垃圾收集器”。它在收集“垃圾”的同时,也负责压缩堆里的所有对象,将“堆指针”移至 

尽可能靠近传送带开头的地方,远离发生(内存)分页错误的地点。垃圾收集器会重新安排所有东西,使其 

成为一个高速、无限自由的堆模型,同时游刃有余地分配存储空间。  

为真正掌握它的工作原理,我们首先需要理解不同垃圾收集器(GC)采取的工作方案。一种简单、但速度较 

慢的GC 技术是引用计数。这意味着每个对象都包含了一个引用计数器。每当一个句柄同一个对象连接起

返回目录 上一页 下一页 回到顶部 0 1

你可能喜欢的