友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第118部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
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 技术是引用计数。这意味着每个对象都包含了一个引用计数器。每当一个句柄同一个对象连接起来
时,引用计数器就会增值。每当一个句柄超出自己的作用域,或者设为null 时,引用计数就会减值。这样一
来,只要程序处于运行状态,就需要连续进行引用计数管理——尽管这种管理本身的开销比较少。垃圾收集
器会在整个对象列表中移动巡视,一旦它发现其中一个引用计数成为 0,就释放它占据的存储空间。但这样
做也有一个缺点:若对象相互之间进行循环引用,那么即使引用计数不是 0,仍有可能属于应收掉的“垃
圾”。为了找出这种自引用的组,要求垃圾收集器进行大量额外的工作。引用计数属于垃圾收集的一种类
型,但它看起来并不适合在所有JVM 方案中采用。
在速度更快的方案里,垃圾收集并不建立在引用计数的基础上。相反,它们基于这样一个原理:所有非死锁
的对象最终都肯定能回溯至一个句柄,该句柄要么存在于堆栈中,要么存在于静态存储空间。这个回溯链可
能经历了几层对象。所以,如果从堆栈和静态存储区域开始,并经历所有句柄,就能找出所有活动的对象。
对于自己找到的每个句柄,都必须跟踪到它指向的那个对象,然后跟随那个对象中的所有句柄,“跟踪追
击”到它们指向的对象……等等,直到遍历了从堆栈或静态存储区域中的句柄发起的整个链接网路为止。中
途移经的每个对象都必须仍处于活动状态。注意对于那些特殊的自引用组,并不会出现前述的问题。由于它
们根本找不到,所以会自动当作垃圾处理。
在这里阐述的方法中,JVM 采用一种“自适应”的垃圾收集方案。对于它找到的那些活动对象,具体采取的
操作取决于当前正在使用的是什么变体。其中一个变体是“停止和复制”。这意味着由于一些不久之后就会
684
…………………………………………………………Page 686……………………………………………………………
非常明显的原因,程序首先会停止运行(并非一种后台收集方案)。随后,已找到的每个活动对象都会从一
个内存堆复制到另一个,留下所有的垃圾。除此以外,随着对象复制到新堆,它们会一个接一个地聚焦在一
起。这样可使新堆显得更加紧凑(并使新的存储区域可以简单地抽离末尾,就象前面讲述的那样)。
当然,将一个对象从一处挪到另一处时,指向那个对象的所有句柄(引用)都必须改变。对于那些通过跟踪
内存堆的对象而获得的句柄,以及那些静态存储区域,都可以立即改变。但在“遍历”过程中,还有可能遇
到指向这个对象的其他句柄。一旦发现这个问题,就当即进行修正(可想象一个散列表将老地址映射成新地
址)。
有两方面的问题使复制收集器显得效率低下。第一个问题是我们拥有两个堆,所有内存都在这两个独立的堆
内来回移动,要求付出的管理量是实际需要的两倍。为解决这个问题,有些JVM 根据需要分配内存堆,并将
一个堆简单地复制到另一个。
第二个问题是复制。随着程序变得越来越“健壮”,它几乎不产生或产生很少的垃圾。尽管如此,一个副本
收集器仍会将所有内存从一处复制到另一处,这显得非常浪费。为避免这个问题,有些JVM 能侦测是否没有
产生新的垃圾,并随即改换另一种方案(这便是“自适应”的缘由)。另一种方案叫作“标记和清除”,Sun
公司的JVM 一直采用的都是这种方案。对于常规性的应用,标记和清除显得非常慢,但一旦知道自己不产生
垃圾,或者只产生很少的垃圾,它的速度就会非常快。
标记和清除采用相同的逻辑:从堆栈和静态存储区域开始,并跟踪所有句柄,寻找活动对象。然而,每次发
现一个活动对象的时候,就会设置一个标记,为那个对象作上“记号”。但此时尚不收集那个对象。只有在
标记过程结束,清除过程才正式开始。在清除过程中,死锁的对象会被释放然而,不会进行任何形式的复
制,所以假若收集器决定压缩一个断续的内存堆,它通过移动周围的对象来实现。
“停止和复制”向我们表明这种类型的垃圾收集并不是在后台进行的;相反,一旦发生垃圾收集,程序就会
停止运行。在Sun 公司的文档库中,可发现许多地方都将垃圾收集定义成一种低优先级的后台进程,但它只
是一种理论上的实验,实际根本不能工作。在实际应用中,Sun 的垃圾收集器会在内存减少时运行。除此以
外,“标记和清除”也要求程序停止运行。
正如早先指出的那样,在这里介绍的JVM 中,内存是按大块分配的。若分配一个大块头对象,它会获得自己
的内存块。严格的“停止和复制”要求在释放旧堆之前,将每个活动的对象从源堆复制到一个新堆,此时会
涉及大量的内存转换工作。通过内存块,垃圾收集器通常可利用死块复制对象,就象它进行收集时那样。每
个块都有一个生成计数,用于跟踪它是否依然“存活”。通常,只有自上次垃圾收集以来创建的块才会得到
压缩;对于其他所有块,如果已从其他某些地方进行了引用,那么生成计数都会溢出。这是许多短期的、临
时的对象经常遇到的情况。会周期性地进行一次完整清除工作——大块头的对象仍未复制(只是让它们的生
成计数溢出),而那些包含了小对象的块会进行复制和压缩。JVM 会监视垃圾收集器的效率,如果由于所有
对象都属于长期对象,造成垃圾收集成为浪费时间的一个过程,就会切换到“标记和清除”方案。类似地,
JVM 会跟踪监视成功的“标记与清除”工作,若内存堆变得越来越“散乱”,就会换回“停止和复制”方
案。“自定义”的说法就是从这种行为来的,我们将其最后总结为:“根据情况,自动转换停止和复制/标
记和清除这两种模式”。
JVM 还采用了其他许多加速方案。其中一个特别重要的涉及装载器以及JIT 编译器。若必须装载一个类(通
常是我们首次想创建那个类的一个对象时),会找到。class 文件,并将那个类的字节码送入内存。此时,一
个方法是用 JIT 编译所有代码,但这样做有两方面的缺点:它会花更多的时间,若与程序的运行时间综合考
虑,编译时间还有可能更长;而且它增大了执行文件的长度(字节码比扩展过的 JIT 代码精简得多),这有
可能造成内存页交换,从而显著放慢一个程序的执行速度。另一种替代办法是:除非确有必要,否则不经
JIT 编译。这样一来,那些根本不会执行的代码就可能永远得不到 JIT 的编译。
由于JVM 对浏览器来说是外置的,大家可能希望在使用浏览器的时候从一些JVM 的速度提高中获得好处。但
非常不幸,JVM 目前不能与不同的浏览器进行沟通。为发挥一种特定JVM 的潜力,要么使用内建了那种JVM
的浏览器,要么只有运行独立的Java 应用程序。
685
…………………………………………………………Page 687……………………………………………………………
附录 F 推荐读物
■《Java in a Nutshell:A Desktop Quick Reference,第2 版》
作者:David Flanagan
出版社:O'Reilly & Assoc
出版时间:1997
简介:对Java 1。1 联机文档的一个简要总结。就个人来说,我更喜欢在线阅览文档,特别是在它们变化得如
此快的时候。然而,许多人仍然喜欢印刷出来的文档,这样可以省一些上网费。而且这本书也提供了比联机
文档更多的讨论。
■《The Java Class Libraries:An Annotated Reference》
作者:Patrick Chan 和Rosanna Lee
出版社:Addison…Wesley
出版时间:1997
简介:作为一种联机参考资源,应向读者提供足够多的说明,使其简单易用。《Thinking in Java》的一名
技术审定员说道:“如果我只能有一本 Java 书,那么肯定选它。”不过我可没有他那么激动。它太大、太
贵,而且示例的质量并不能令我满意。但在遇到麻烦的时候,该书还是很有参考价值的。而且与《Java in a
Nutshell 》相比,它看起来有更大的深度(当然也有更多的文字)。
■《Java Network Programming》
作者:Elliote Rusty Harold
David Flanagan
出版社:O'Reilly
出版时间:1997
简介:在阅读本书前,我可以说根本不理解Java 有关网络的问题。后来,我也发现他的 Web 站点“Cafe au
Lait ”是个令人激动的、很人个性的以及经常更新的去处,涉及大量有价值的 Java 开发资源。由于几乎每天
更新,所以在这里能看到与Java 有关的大量新闻。站点地址是:http://sunsite。unc。edu/javafaq/ 。
■《Core Java,第3 版》
作者:Cornel 和 Horstmann
出版社:Prentice…Hall
出版时间:1997
简介:对于自己碰到的问题,若在《Thinking in Java》里找不到答案,这就是一个很好的参考地点。注
意:Java 1。1 的版本是《Core Java 1。1 Volume 1…Fundamentals & Core Java 1。1 Volume 2 …Advanced
Features》
■《JDBC Database Access with Java》
作者:Hamilton ,Cattell 和Fisher
出版社:Addison…Wesley
出版时间:1997
简介:如果对SQL 和数据库一无所知,这本书就可以作为一个相当好的起点。它也对API 进行了详尽的解
释,并提供一个“注释参考。与“Java 系列”(由 JavaSoft 授权的唯一一套丛书)的其他所有书籍一样,
这本书的缺点也是进行了过份的渲染,只说Java 的好话——在这一系列书籍里找不到任何不利于Java 的地
方。
■《Java Programming with CORBA》
作者:Andreas Vogel 和Keith Duddy
出版社:Jonh Wiley & Sons
出版时间:1997
简介:针对三种主要的 Java ORB (Visbroker,Orbix,Joe),本书分别用大量代码实例进行了详尽的阐
686
…………………………………………………………Page 688……………………………………………………………
述。
■《Design Patterns》
作者:Gamma,Helm ,Johnson 和 Vlissides
出版社:Addison…Wesley
出版时间:1995
简介:这是一本发起了编程领域方案革命的经典书籍。
■《UML Toolkit》
作者:Hans…Erik Eriksson 和Magnus Penker
出版社:Jonh Wiley & Sons
出版时间:1997
简介:解释 UML 以及如何使用它,并提供Java 的实际案例供参考。配套CD…ROM 包含了 Java 代码以及
Rational Rose 的一个删减版本。本书对UML 进行了非常出色的描述,并解释了如何用它构建实际的系统。
■《Practical Algorithms for Programmers 》
作者:Binstock 和Rex
出版社:Addison…Wesley
出版时间:1995
简介:算法是用C 描述的,所以它们很容易就能转换到Java 里面。每种算法都有详尽的解释。
687
………………………………………………………………………用户上传之内容结束……………………………………………………………………………………
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!