深入理解Java虚拟机:JVM高级特性与最佳实践(txt+pdf+epub+mobi电子书下载)


发布时间:2020-08-05 21:05:38

点击下载

作者:周志明

出版社:机械工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

深入理解Java虚拟机:JVM高级特性与最佳实践

深入理解Java虚拟机:JVM高级特性与最佳实践试读:

前言

Java是目前用户最多、使用范围最广的软件开发技术,Java的技术体系主要由支撑Java程序运行的虚拟机、为各开发领域提供接口支持的Java API、Java编程语言及许许多多的第三方Java框架(如Spring和Struts等)构成。在国内,有关Java API、Java语言及第三方框架的技术资料和书籍非常丰富,相比之下,有关Java虚拟机的资料却显得异常贫乏。

这种状况很大程度上是由Java开发技术本身的一个重要优点导致的:在虚拟机层面隐藏了底层技术的复杂性以及机器与操作系统的差异性。运行程序的物理机器情况千差万别,而Java虚拟机则在千差万别的物理机上面建立了统一的运行平台,实现了在任意一台虚拟机上编译的程序都能在任何一台虚拟机上正常运行。这一极大的优势使得Java应用的开发比传统C/C++应用的开发更高效和快捷,程序员可以把主要精力集中在具体业务逻辑上,而不是物理硬件的兼容性上。一般情况下,一个程序员只要了解了必要的Java API、Java语法并学习适当的第三方开发框架,就已经基本能满足日常开发的需要了,虚拟机会在用户不知不觉中完成对硬件平台的兼容以及对内存等资源的管理工作。因此,了解虚拟机的运作并不是一般开发人员必须掌握的知识。

然而,凡事都具备两面性。随着Java技术的不断发展,它被应用于越来越多的领域之中。其中一些领域,如电力、金融、通信等,对程序的性能、稳定性和可扩展性方面都有极高的要求。一个程序很可能在10个人同时使用时完全正常,但是在10000个人同时使用时就会变慢、死锁甚至崩溃。毫无疑问,要满足10000个人同时使用需要更高性能的物理硬件,但是在绝大多数情况下,提升硬件效能无法等比例地提升程序的性能和并发能力,有时甚至可能对程序的性能没有任何改善作用。这里面有Java虚拟机的原因:为了达到为所有硬件提供一致的虚拟平台的目的,牺牲了一些硬件相关的性能特性。更重要的是人为原因:开发人员如果不了解虚拟机的一些技术特性的运行原理,就无法写出最适合虚拟机运行和可自优化的代码。

其实,目前商用的高性能Java虚拟机都提供了相当多的优化特性和调节手段,用于满足应用程序在实际生产环境中对性能和稳定性的要求。如果只是为了入门学习,让程序在自己的机器上正常运行,那么这些特性可以说是可有可无的;如果用于生产环境,尤其是企业级应用开发中,就迫切需要开发人员中至少有一部分人对虚拟机的特性及调节方法具有很清晰的认识,所以在Java开发体系中,对架构师、系统调优师、高级程序员等角色的需求一直都非常大。学习虚拟机中各种自动运作的特性的原理也成为了Java程序员成长道路上必然会接触到的一课。通过本书,读者可以以一种相对轻松的方式学习虚拟机的运作原理,对Java程序员的成长也有较大的帮助。

本书读者对象(1)使用Java技术体系的中、高级开发人员

Java虚拟机作为中、高级开发人员必须修炼的知识,有着较高的学习门槛,本书可作为学习虚拟机的优秀教材。(2)系统调优师

系统调优师是近几年才兴起的职业,本书中的大量案例、代码和调优实战将会对系统调优师的日常工作有直接的帮助。(3)系统架构师

保障系统高效、稳定和可伸缩是系统架构师的主要职责之一,而这与虚拟机的运作密不可分,本书可以作为他们设计应用系统底层框架的参考资料。

如何阅读本书

本书一共分为五个部分:走近Java、自动内存管理机制、虚拟机执行子系统、程序编译与代码优化、高效并发。各个部分基本上是相互独立的,没有必然的前后依赖关系,读者可以从任何一个感兴趣的专题开始阅读,但是每个部分中的各个章节间有先后顺序。

本书并不假设读者在Java领域具备很专业的技术水平,因此在保证逻辑准确的前提下,尽量用通俗的语言和案例讲述虚拟机中与开发关系最为密切的内容。当然学习虚拟机技术本身就需要读者有一定的技术基础,且本书的读者定位是中、高级程序员,因此本书假设读者自己了解一些常用的开发框架、Java API和Java语法等基础知识。

语言约定

本书在语言和技术上有如下的约定:

·本书中提到HotSpot虚拟机、JRockit虚拟机、WebLogic服务器等产品的所有者时,仍然使用Sun和BEA公司的名称。实际上BEA和Sun分别于2008年和2010年被Oracle公司收购,现在已经不存在这两个商标了,但是毫无疑问它们都是对Java领域做出过卓越贡献的、值得程序员纪念的公司。

·JDK从1.5版本开始,在官方的正式文档与宣传资料中已经不再使用类似“JDK 1.5”的名称,只有在程序员内部使用的开发版本号(Developer Version,例如java-version的输出)中才继续沿用1.5、1.6和1.7的版本号,而公开版本号(Product Version)则改为JDK 5、JDK 6和JDK 7的命名方式。为了行文一致,本书所有场合统一采用开发版本号的命名方式。

·由于版面关系,本书中的许多示例代码都没有遵循最优的代码编写风格,如使用的流没有关闭流等,请读者在阅读时注意这一点。

·如果没有特殊说明,本书中所有的讨论都是以Sun JDK 1.6为技术平台的。不过如果有某个特性在各个版本间的变化较大,一般都会说明它在各个版本间的差异。

内容特色

第一部分 走近Java

本书的第一部分为后文的讲解建立了良好的基础。尽管了解Java技术的来龙去脉,以及编译自己的OpenJDK对于读者理解Java虚拟机并不是必需的,但是这些准备过程可以为走近Java技术和Java虚拟机提供很好的引导。第一部分只有第1章:

第1章 介绍了Java技术体系的过去、现在和未来的发展趋势,并介绍了如何独立编译一个OpenJDK 7。

第二部分 自动内存管理机制

因为程序员把内存控制的权力交给了Java虚拟机,所以可以在编码的时候享受自动内存管理的诸多优势,不过也正因为这个原因,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会成为一项异常艰难的工作。第二部分包括第2~5章:

第2章 讲解了虚拟机中的内存是如何划分的,哪部分区域、什么样的代码和操作可能导致内存溢出异常,并讲解了各个区域出现内存溢出异常的常见原因。

第3章 分析了垃圾收集的算法和JDK 1.6中提供的几款垃圾收集器的特点及运作原理,通过代码实例验证了Java虚拟机中的自动内存分配及回收的主要规则。

第4章 介绍了随JDK发布的6个命令行工具与2个可视化的故障处理工具的使用方法。

第5章 与读者分享了几个比较有代表性的实际案例,还准备了一个所有开发人员都能“亲身实战”的练习,读者可通过实践来获得故障处理和调优的经验。

第三部分 虚拟机执行子系统

执行子系统是虚拟机中必不可少的组成部分,了解了虚拟机如何执行程序,才能写出更优秀的代码。第三部分包括第6~9章:

第6章 讲解了Class文件结构中的各个组成部分,以及每个部分的定义、数据结构和使用方法,以实战的方式演示了Class的数据是如何存储和访问的。

第7章 介绍了在类加载过程的“加载”、“验证”、“准备”、“解析”和“初始化”这五个阶段中虚拟机分别执行了哪些动作,还介绍了类加载器的工作原理及其对虚拟机的意义。

第8章 分析了虚拟机在执行代码时如何找到正确的方法,如何执行方法内的字节码,以及执行代码时涉及的内存结构。

第9章 通过四个类加载及执行子系统的案例,分享了使用类加载器和处理字节码的一些值得欣赏和借鉴的思路,并通过一个实战练习来加深对前面理论知识的理解。

第四部分 程序编译与代码优化

Java程序从源码编译成字节码和从字节码编译成本地机器码的这两个过程,合并起来其实就等同于一个传统编译器所执行的编译过程。第四部分包括第10和11章:

第10章 分析了Java语言中的泛型、自动装箱拆箱、条件编译等多种语法糖的前因后果,并通过实战案例演示了如何使用插入式注解处理器来实现一个检查程序命名规范的编译器插件。

第11章 讲解了虚拟机的热点探测方法、HotSpot的即时编译器、编译触发条件,以及如何从虚拟机外部观察和分析JIT编译的数据和结果。此外,还讲解了几种常见的编译期优化技术。

第五部分 高效并发

Java语言和虚拟机提供了原生的、完善的多线程支持,使得它天生就适合开发多线程并发的应用程序。不过我们不能期望系统来完成所有与并发相关的处理,了解并发的内幕也是一个高级程序员不可缺少的课程。第五部分包括第12和13章:

第12章 讲解了虚拟机的Java内存模型的结构和操作,以及原子性、可见性和有序性在Java内存模型中的体现,介绍了先行发生原则及使用,还讲解了线程在Java语言中是如何实现的。

第13章 介绍了线程安全所涉及的概念和分类、同步实现的方式以及虚拟机的底层运作原理,并且还介绍了虚拟机实现高效并发所采取的一系列锁优化措施。

参考资料

本书名为“深入理解Java虚拟机”,但要想真的深入理解虚拟机,仅凭一本书肯定是远远不够的,读者可以通过下面的信息找到更多关于Java虚拟机方面的资料。我在写作此书的时候,也从下面这些参考资料中获得了很大的帮助。(1)书籍[1]

·《The Java Virtual Machine Specification,Second Edition》《Java虚拟机规范(第2版)》,1999年4月出版。国内并没有引进这本书,自然也就没有中文译本,但全书的电子版是免费发布的,[2]在IT书籍中它已经非常“高寿”了(这本书的第3版已处于基本完成的草稿状态,在JDK 1.7正式版发布后这本书应该就会推出第3版)。要学习虚拟机,虚拟机规范无论如何都是必须读的。这本书的概念和细节描述与Sun的早期虚拟机(Sun Classic VM)高度吻合,不过,随着技术的发展,高性能虚拟机真正的细节实现方式与虚拟机规范所描述的差距已经越来越大。但是,如果只能选择一本参考书来了解虚拟机的话,那仍然是这本书。[3]

·《The Java Language Specification,Third Edition》《Java语言规范(第3版)》,2005年7月由机械工业出版社出版,不过出版的是影印版,没有中文译本。虽然Java虚拟机并不是Java语言专有的,但是了解Java语言的各种细节规定对虚拟机的行为也是很有帮助的,它与《Java虚拟机规范(第2版)》都是Sun官方出品的书籍,而且这本书还是由Java之父James Gosling亲自撰写的。

·《Oracle JRockit The Definitive Guide》《Oracle JRockit权威指南》,2010年7月出版,国内也没有(可能是尚未)引进这本书,它是由JRockit的两位资深开发人员(其中一位是JRockit Mission Control团队的TeamLeader)撰写的高级JRockit虚拟机使用指南。虽然JRockit的用户量可能不如HotSpot多,但也是最流行的三大商业虚拟机之一,并且不同虚拟机中的很多实现思路都是可以对比参照的。这本书是了解现代高性能虚拟机的很好的途径。

·《Inside the Java 2Virtual Machine,Second Edition》《深入Java虚拟机(第2版)》,2000年1月出版,2003年机械工业出版社出版了中文译本。在相当长的时间里,这本书是唯一一本关于Java虚拟机的中文图书。(2)网站资源

·高级语言虚拟机圈子:http://hllvm.group.iteye.com/

里面有一些国内关于虚拟机的讨论,并不只限于JVM,而是涉及对所有的高级语言虚拟机(High-Level Language Virtual Machine)的[4]讨论,但该网站建立在ITEye上,自然还是以讨论Java虚拟机为主。圈主撒迦(莫枢)的博客(http://rednaxelafx.iteye.com/)是另外一个非常有价值的虚拟机及编译原理等资料的分享园地。

·HotSpot Internals:http://wikis.sun.com/display/HotSpotInternals/Home

一个关于OpenJDK的Wiki网站,许多文章都由JDK的开发团队编写,更新很慢,但是仍然有很大的参考价值。

·The HotSpot Group:http://openjdk.java.net/groups/hotspot/

HotSpot组群,包含虚拟机开发、编译器、垃圾收集和运行时四个邮件组,其中有关于HotSpot虚拟机的最新讨论。

联系作者

在本书完稿时,我并没有像想象中那样兴奋或放松,写作时的那种“战战兢兢、如履薄冰”的感觉依然萦绕在心头。在每一章、每一节落笔之时,我都在考虑如何才能把各个知识点更有条理地讲述出来,都在担心会不会由于自己理解有偏差而误导了大家。囿于我的写作水平和写作时间,书中难免存在不妥之处,所以特地开通了一个读者邮箱(understandingjvm@gmail.com)与大家交流,大家如有任何意见或建议都欢迎与我联系。此外,大家也可以通过我的微博(http://t.sina.com.cn//icyfenix)与我取得联系。

勘误

写书和写代码一样,刚开始都是不完美的,需要不断地修正和重构,本书也不例外。如果大家在阅读本书的过程中发现了本书中存在的任何问题,都欢迎反馈给我们。我们会把本书的勘误集中公布在icyfenx.iteye.com/blog/1119214。[1] 官方地址:http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html。[2] 在这十多年间虚拟机规范的更新可以通过JSR-924 规范来跟踪,JSR-924 规范的地址为:http://jcp.org/aboutJava/communityprocess/maintenance/jsr924/index3.html。[3] 官方地址:http://java.sun.com/docs/books/jls/download/langspec-3.0.pdf。[4] 该网站原名为JavaEye,近期更名为ITEye。

致谢

首先要感谢我的家人,全靠家人在本书写作期间对我的悉心照顾,才让我能够全身心地投入到写作之中,而无后顾之忧。

同时要感谢我的工作单位远光软件,公司为我提供了宝贵的工作、学习和实践的环境,本书中的许多知识点都来自于工作中的实践;也感谢与我一起工作的同事们,非常荣幸能与你们一起在这个富有激情的团队中共同奋斗。

还要感谢淘宝网的莫枢(rednaxelafx.iteye.com)在百忙之中抽空审阅了本书,提出了许多宝贵的建议和意见。

最后,感谢机械工业出版社华章公司的编辑们,本书能够顺利出版,离不开他们的敬业精神和一丝不苟的工作态度。周志明2011年5月第一部分走近Java第1章 走近Java本章主要内容·概述·Java技术体系·Java发展史·展望Java技术的未来·实战:自己编译JDK世界上并没有完美的程序,但我们并不因此而沮丧,因为写程序本来就是一个不断追求完美的过程。1.1 概述

Java不仅仅是一门编程语言,它还是一个由一系列计算机软件和规范形成的技术体系,这个技术体系提供了完整的用于软件开发和跨平台部署的支持环境,并广泛应用于嵌入式系统、移动终端、企业服务器和大型机等各种场合,如图1-1所示。时至今日,Java技术体系已经吸引了600多万软件开发者,这是全球最大的软件开发团队。使用Java的设备多达几十亿台,其中包括8亿多台个人计算机、21亿部移动电话及其他手持设备、35亿个智能卡,以及大量机顶盒、导航[1]系统和其他设备。

Java能获得如此广泛的认可,除了因为它拥有一门结构严谨、面向对象的编程语言之外,还有许多不可忽视的优点:它摆脱了硬件平台的束缚,实现了“一次编写,到处运行”的理想;它提供了一种相对安全的内存管理和访问机制,避免了绝大部分的内存泄漏和指针越界问题;它实现了热点代码检测和运行时编译及优化,这使得Java应用能随着运行时间的增加而获得更高的性能;它有一套完善的应用程序接口,还有无数的来自商业机构和开源社区的第三方类库来帮助实现各种各样的功能……Java所带来的这些好处让程序的开发效率得到了很大的提升。作为一名Java程序员,在编写程序时除了尽情发挥Java的各种优势外,还应该去了解和思考一下Java技术体系中这些技术是如何实现的。认清这些技术的运作本质,是自己思考“程序这样写好不好”的基础和前提。当我们在使用一门技术时,如果不再依赖书本和他人就能得到这个问题的答案,那才算升华到了“不惑”的境界。图1-1 Java技术的广泛应用

本书将会与读者一起分析Java技术中最重要的那些特性的实现原理。在本章中,我们将重点介绍Java技术体系所包括的内容,以及Java的历史、现在和未来的发展趋势。[1] 这些数据是Java 的广告词,它们来源于:http://www.java.com/zh_CN/about/。1.2 Java技术体系

从广义上讲,Clojure、JRuby、Groovy等运行于Java虚拟机上的语言及其相关的程序都属于Java技术体系的一员。如果仅从传统意义上来看,Sun官方所定义的Java技术体系包括了以下几个组成部分:

·Java程序设计语言

·各种硬件平台上的Java虚拟机

·Class文件格式

·Java API类库

·来自商业机构和开源社区的第三方Java类库

我们可以把Java程序设计语言、Java虚拟机、Java API类库这三部分统称为JDK(Java Development Kit),JDK是用于支持Java程序开发的最小环境,在后面的内容中,为了讲解方便,有一些地方会以JDK来代替整个Java技术体系。另外,可以把Java API类库中的Java [1]SE API子集和Java虚拟机这两部分统称为JRE(Java Runtime Environment),JRE是支持Java程序运行的标准环境。图1-2展示了Java技术体系所包括的内容,以及JDK和JRE所涵盖的范围。[2]图1-2 Java技术体系所包括的内容

以上是根据各个组成部分的功能来进行划分的,如果按照技术所服务的领域来划分,或者说按照Java技术关注的重点业务领域来划分,Java技术体系可以分为四个平台,分别为:

·Java Card:支持一些Java小程序(Applets)运行在小内存设备(如智能卡)上的平台。

·Java ME(Micro Edition):支持Java程序运行在移动终端(手机、PDA)上的平台,对Java API有所精简,并加入了针对移动终端的支持,这个版本以前称为J2ME。

·Java SE(Standard Edition):支持面向桌面级应用(如Windows下的应用程序)的Java平台,提供了完整的Java核心API,这个版本以前称为J2SE。

·Java EE(Enterprise Edition):支持使用多层架构的企业应用(如ERP、CRM应用)的Java平台,除了提供Java SE API外,还对[3]其做了大量的扩充并提供了相关的部署支持,这个版本以前称为J2EE。[1] JDK 1.6 的Java SE API 范围:http://download.oracle.com/javase/6/docs/api/。[2] 图片来源:http://download.oracle.com/javase/6/docs/。[3] 这些扩展一般以javax.*作为包名,而以java.*为包名的包都是Java SE API的核心包,但由于历史原因,一部分曾经是扩展包的API后来进入了核心包,因此核心包中也包含了不少javax.*的包名。1.3 Java发展史

从第一个Java版本诞生到现在已经有16年的时间了。沧海桑田一瞬间,转眼16年过去了,在图1-3所展示的时间线中,我们看到JDK已经发展到了1.7版。在这16年里还诞生了无数和Java相关的产品、技术和标准。现在让我们进入时间隧道,从孕育Java语言的时代开始,再来回顾一下Java的发展轨迹和历史变迁。图1-3 Java技术发展的时间线

1991年4月,由James Gosling博士领导的绿色计划(Green Project)开始启动,此计划的目的是开发一种能够在各种消费性电子产品(如机顶盒、冰箱、收音机等)上运行的程序架构。这个计划的产品就是Java语言的前身:Oak(橡树)。Oak当时在消费品市场上并不算成功,但随着1995年互联网潮流的兴起,Oak迅速找到了最适合自己发展的市场定位并蜕变成为Java语言。

1995年5月23日,Oak语言改名为Java,并且在SunWorld大会上正式发布了Java1.0版本。Java语言第一次提出了“Write Once,Run Anywhere”的口号。

1996年1月23日,JDK 1.0发布,Java语言有了第一个正式版本的运行环境。JDK 1.0提供了一个纯解释执行的Java虚拟机实现(Sun Classic VM)。JDK 1.0版本的代表技术包括:Java虚拟机、Applet和AWT等。

1996年4月,10个最主要的操作系统供应商声明将在其产品中嵌入Java技术。同年9月,已有大约8.3万个网页应用Java技术来制作。在1996年5月底,Sun于美国旧金山举行了首届JavaOne大会,从此JavaOne成为全世界数百万Java语言开发者每年一度的技术盛会。

1997年2月19日,Sun发布了JDK 1.1,Java技术的一些最基础的支撑点(如JDBC等)都是在JDK 1.1版本中发布的,JDK 1.1的技术代表有:JAR文件格式、JDBC、JavaBeans、RMI。Java语法也有了一定的发展,如内部类(Inner Class)和反射(Reflection)都是在这个时候出现的。

直到1999年4月8日,JDK 1.1一共发布了1.1.0至1.1.8九个版本。从1.1.4之后,每个JDK版本都有一个自己的名字(工程代号),分别为:JDK 1.1.4-Sparkler(宝石)、JDK 1.1.5-Pumpkin(南瓜)、JDK 1.1.6-Abigail(阿比盖尔,女子名)、JDK 1.1.7-Brutus(布鲁图,古罗马政治家和将军)和JDK 1.1.8-Chelsea(切尔西,城市名)。

1998年12月4日,JDK迎来了一个里程碑式的版本JDK 1.2,工程代号为Playground(竞技场),Sun在这个版本中把Java技术体系拆分为3个方向,分别是面向桌面应用开发的J2SE(Java 2Platform,Standard Edition)、面向企业级开发的J2EE(Java 2Platform,Enterprise Edition)和面向手机等移动终端开发的J2ME(Java 2Platform,Micro Edition)。在这个版本中出现的代表性技术非常多,如EJB、Java Plug-in、Java IDL、Swing等,并且在这个版本中Java虚拟机第一次内置了JIT(Just In Time)编译器(JDK 1.2中曾并存过3个虚拟机,分别是Classic VM、Hot Spot VM和Exact VM,其中Exact VM只在Solaris平台出现过;后面2个虚拟机都是内置JIT编译器的,而之前的版本所带的Classic VM只能以外挂形式使用JIT编译器)。在语言和API级别上,Java添加了strictfp关键字与现在Java编码之中极为常用的一系列Collections集合类。在1999年3月和7月,分别有JDK 1.2.1和JDK 1.2.2两个小版本发布。

1999年4月27日,HotSpot虚拟机发布,HotSpot最初由一家名为“Longview Technologies”的小公司开发,因为HotSpot的优异表现,这家公司在1997年被Sun公司收购了。HotSpot虚拟机发布时是作为JDK 1.2的附加程序提供的,后来它成为了JDK 1.3及之后所有版本的Sun JDK的默认虚拟机。

2000年5月8日,工程代号为Kestrel(美洲红隼)的JDK 1.3发布,JDK 1.3相对于JDK 1.2的改进主要表现在一些类库(如数学运算和新的Timer API等)上,JNDI服务从JDK 1.3开始被作为一项平台级服务提供(以前JNDI仅仅是一项扩展),使用CORBA IIOP来实现RMI的通讯协议,等等。这个版本还对Java 2D做了很多改进,提供了大量新的Java 2D API,并且新添加了JavaSound类库。JDK 1.3有1个修正版本JDK 1.3.1,工程代号为Ladybird(瓢虫)于2001年5月17日发布。

自从JDK 1.3开始,Sun维持了一个习惯:大约每隔两年发布一个JDK的主版本,以动物名称命名,期间发布的各个修正版本则以昆虫名称作为工程名称。

2002年2月13日,JDK 1.4发布,工程代号为Merlin(灰背隼)。JDK 1.4是Java真正走向成熟的一个版本,Compaq、Fujitsu、SAS、Symbian、IBM等著名公司都有参与甚至实现自己独立的JDK 1.4。哪怕是在近10年后的今天,仍然有许多主流应用(Spring、Hibernate、Struts等)能直接运行在JDK 1.4之上,或者继续发布能运行在1.4上的版本。JDK 1.4同样发布了很多新的技术特性,如正则表达式、异常链、NIO、日志类、XML解析器和XSLT转换器,等等。JDK 1.4有两个后续修正版:2002年9月16日发布的工程代号为Grasshopper(蚱蜢)的JDK 1.4.1与2003年6月26日发布的工程代号为Mantis(螳螂)的JDK 1.4.2。

2002年前后还发生了一件与Java没有直接关系,但事实上对Java的发展进程影响很大的事件,即微软的.NET Framework发布。这个无论是技术实现还是目标用户上都与Java有很多相近之处的技术平台给Java带来了很多讨论、比较和竞争,.NET平台和Java平台之间声势浩大的孰优孰劣的论战到今天为止仍然在继续。[1]

2004年9月30日,JDK 1.5发布,工程代号为Tiger(老虎)。从JDK 1.2以来,Java在语法层面上的变化一直很小,而JDK 1.5在Java语法易用性上做出了非常大的改进。自动装箱、泛型、动态注解、枚举、可变长参数、遍历循环(foreach循环)等语法特性都是在JDK 1.5中加入的。在虚拟机和API层面上,这个版本改进了Java的内存模型(Java Memory Model,JMM)、提供了java.util.concurrent并发包等。另外,JDK 1.5是官方声明可以支持Windows 9x平台的最后一个JDK版本。

2006年12月11日,JDK 1.6发布,工程代号为Mustang(野马)。这是目前为止最新的正式版JDK(截至本书完稿时,JDK 1.7仍然处于Early Access版本)。在这个版本中,Sun终结了从JDK 1.2开始已经有8年历史的J2EE、J2SE、J2ME的命名方式,启用了Java SE 6、Java EE 6、Java ME 6的命名来代替。JDK 1.6的改进包括:提供动态语言支持(通过内置Mozilla JavaScript Rhino引擎实现)、提供编译API和微型HTTP服务器API,等等。同时,这个版本对Java虚拟机的内部做了大量改进,包括锁与同步、垃圾收集、类加载等方面的算法都有相当多的改动。

在2006年11月13日的JavaOne大会上,Sun宣布最终会把Java开源,并在随后的一年多时间内,陆续地在GPL v2(GNU General Public License v2)协议下公开了JDK各个部分的源码,并建立了OpenJDK组织对这些源码进行独立管理。除了极少量的产权代码(Encumbered Code,这部分代码大多是Sun本身也无权限进行开源处理的)外,OpenJDK几乎包括了Sun JDK的全部代码。OpenJDK的质量主管曾经表示,在JDK 1.7中,Sun JDK和OpenJDK除了代码文件头的版权注释之外,代码基本上完全一样,所以OpenJDK 7与Sun JDK 1.7本质上就是同一套代码库出来的产品。

JDK 1.6发布以后,由于代码复杂性的增加、JDK开源、开发JavaFX、经济危机及Sun收购案等原因,Sun在JDK发展以外的事情上耗费了很多资源,JDK的更新没有再维持两年发布一个主版本的发展速度。JDK 1.6到今天为止一共发布了25个Update,最新的版本为Java SE 6Update 25,于2011年4月21日发布。

2009年2月19日,工程代号为Dolphin(海豚)的JDK 1.7完成了其第一个里程碑版本。根据JDK 1.7的功能规划,一共设置了10个里程碑。最后一个里程碑版本于2010年9月9日结束。从发布的Early Access版看来目前JDK 1.7的主体功能,已经比较完善,只剩下Lambda项目(Lambda表达式)、Jigsaw(模块化支持)和Coin(语言细节进化)子项目的部分工作尚未完成,Oracle宣布JDK 1.7正式[2]版将于2011年7月28日推出,可能会把不能按时完成的Lambda、Jigsaw和部分Coin放入JDK 1.8之中。JDK 1.7的主要改进包括:提供新的G1收集器、加强对非Java语言的调用、语言级的模块化支持(取决于Jigsaw项目能不能完成)、升级类加载架构,等等。

2009年4月20日,Oracle宣布正式以74亿美元的价格收购Sun公司,Java商标从此正式归Oracle所有(Java语言本身并不属于哪家公司所有,它由JCP组织进行管理,尽管JCP主要是由Sun或者说Oracle所领导的)。由于此前Oracle已经收购了另外一家大型的中间件企业BEA公司,当完成对Sun公司的收购之后,Oracle分别从BEA和Sun中取得了目前三大商业虚拟机的其中两个:JRockit和HotSpot,Oracle宣布在未来1至2年的时间内,将把这两个优秀的虚[3]拟机互相取长补短,最终合二为一。可以预见在不久的将来,Java技术体系将会产生相当巨大的变化。[1] JDK从1.5版本开始,官方在正式文档与宣传上已经不再使用类似JDK 1.5的命名,只有程序员内部使用的开发版本号(Developer Version,例如java-version的输出)中才继续沿用1.5、1.6、1.7的版本号,而公开版本号(Product Version)则改为JDK 5、JDK 6、JDK 7的命名方式,本书为了行文一致,所有场合统一采用开发版本号的命名方式。[2] 在本书初稿完成之际,已收到确定消息证实Jigsaw、Lambda等项目无法在JDK 7中发布,最早将在JDK8中提供。[3] Hot Roekit项目的相关介绍:http://hirt.se/presentations/WhatToExpect.ppt。1.4 展望Java技术的未来

在Java语言诞生10周年(2005年)的SunOne技术大会上,Java语言之父James Gosling做过一个题为“Java技术的下一个十年”的演讲。笔者不具备James Gosling博士那样高屋建瓴的视角,这里仅从Java平台中几个新生的但已经开始展现出蓬勃之势的技术发展点来看一下后续1至2个JDK版本内的一些很有希望的技术重点。1.4.1 模块化

模块化是解决应用系统与技术平台越来越复杂、越来越庞大而产生的一系列问题的一个重要途径。无论是开发人员还是产品的最终用户,都不希望为了系统中的一小块功能而不得不下载、安装、部署及维护整套庞大的系统。最近几年OSGi技术的迅速发展正说明了通过模块化实现按需部署、降低复杂性和维护成本的需求是相当迫切的。

预计在未来的Java平台中,将会对模块化提供语法层面的支持。在Java SE 7发展初期,两个重要的JSR曾经试图解决依赖关系管理问题,分别是JSR-294:Java编程语言中的改进模块性支持(Improved Modularity Support in the Java Programming Language)和JSR-277:Java模块系统(Java Module System),两者分别关注Java模块概念的开发和部署方面。在具体实现方面,Java SE 7中已建立了一个名为Jigsaw(拼图)的项目来推动这两个规范在Java平台中转变为具体的实现。1.4.2 混合语言

当单一的Java语言已经无法满足当前软件的复杂需求时,越来越多基于Java虚拟机的语言被应用到软件项目中。Java平台上的多语言混合编程正成为主流,每种语言都可以针对自己擅长的方面更好地解决问题。试想一下,在一个项目之中,并行处理用Clojure语言编写,展示层使用JRuby/Rails,中间层则是Java,每个应用层都将使用不同的编程语言来完成,而且,接口对每一层的开发者都是透明的,各种语言之间的交互不存在任何困难,就像使用自己语言的原生API一[1]样方便,因为它们最终都运行在一个虚拟机之上。

在最近两年里,Clojure、JRuby、Groovy等新生语言的使用人数如同滚动的雪球一般增长,而运行在Java虚拟机之上的语言数量也在迅速膨胀,图1-4中列举了其中的一部分。这两点证明混合编程在我们身边已经有所应用并被广泛认可。通过特定领域的语言去解决特定领域的问题是当前软件开发应对日趋复杂的项目需求的一个方向。[2]图1-4 可以运行在JVM之上的语言

除了催生出大量的新语言外,许多已经有很长历史的程序语言也出现了基于Java虚拟机实现的版本。这样的混合编程对许多以前使用其他语言的“老”程序员也有相当大的吸引力,软件企业投入了大量资本的现有代码资产也能被很好地保护起来。表1-1中列举了常见语言的Java虚拟机实现版本。表1-1 常见语言的JVM实现版本1.4.3 多核并行

如今,CPU硬件的发展方向已经从高频率转变为多核心,随着多核时代的来临,软件开发越来越关注并行编程的领域。早在JDK 1.5之中就已经引入java.util.concurrent包实现了一个粗粒度的并发框架,而JDK 1.7中将会加入的java.util.concurrent.forkjoin包则是对这个框架的一次重要扩充。Fork/Join模式是处理并行编程的一种经典方法,如图1-5所示。虽然不能解决所有的问题,但是在它的适用范围之内,能够轻松地利用多个CPU核心提供的计算资源来协作完成一个复杂的计算任务。通过利用Fork/Join模式,我们能够更加顺畅地过渡到多核的时代。[3]图1-5 Fork/Join模式示意图

在JDK外围,也出现了专为满足并行计算需求的计算框架,如Apache的Hadoop Map/Reduce,这是一个简单易懂的并行框架,能够运行在由上千个商用机器组成的大型集群上,并能以一种可靠的容错方式并行处理上TB级别的数据集。另外,还出现了诸如Scala、Clojure及Erlang等天生就具备并行计算能力的语言。1.4.4 进一步丰富语法

JDK 1.5曾经对Java语法进行了一次扩充,这次扩充加入了自动装箱、泛型、动态注解、枚举、可变长参数、遍历循环等语法特性,使得Java语言的精确性和易用性有了很大的进步。在JDK 1.7(由于进度压力,许多改进已被推迟至JDK 1.8)中,将会对Java语法进行[4]另一次大规模的扩充。Sun(Oracle)为此发起了Coin子项目来统一处理对Java语法的细节修改,如二进制数的原生支持、在switch语句中支持字符串、“<>”操作符、异常处理的改进、简化变长参数方法调用、面向资源的try-catch-finally语句等都是在Coin项目之中提交的内容。另外,JSR-335(Lambda Expressions for the Java TM [5]Programming Language)中定义的Lambda表达式也将对Java的语法和语言习惯产生很大的影响,函数式编程可能会成为主流。1.4.5 64位虚拟机

几年之前,主流的CPU就开始支持64位架构。Java虚拟机也在很早之前就推出了支持64位系统的版本。但Java程序运行在64位虚拟机上需要付出比较大的额外代价:首先是内存问题,由于指针膨胀和各种数据类型对齐补白的原因,运行于64位系统上的Java应用需要消耗更多的内存,通常要比32位系统额外增加10%~30%的内存消耗;其次是多个机构的测试结果显示,64位虚拟机的运行速度在各个测试项上几乎都全面落后于32位虚拟机,两者大约有15%左右的性能差距。

但是在Java EE方面,企业级应用经常需要使用超过4G的内存,对于64位虚拟机的需求是非常迫切的,由于上述的原因,许多企业应用都仍然选择使用虚拟集群等方式继续在32位虚拟机中进行部署。Sun也注意到了这些问题,并做出了一些改善,在JDK 1.6Update 14之后,提供了普通对象指针压缩功能(-XX:+UseCompressedOops),在解释器解释字节码时,植入压缩指令以节省内存消耗。随着硬件的进一步发展,计算机终究会完全过渡到64位的时代,这是一件毫无疑问的事情,主流的虚拟机应用终究也会从32位发展至64位,而虚拟机对64位的支持也将会进一步完善。[1] 在同一个虚拟机上运行的其他语言与Java语言之间的交互一般都比较容易,但非Java语言之间的交互一般都比较繁琐。dynalang项目(http://dynalang.sourceforge.net/)就是为了解决这个问题而出现的。[2] 图片来源:http://wikis.sun.com/download/attachments/16418319/OOW-2009+Towards+A+Universal+VM.pdf。[3] 图片来源:http://www.ibm.com/developerworks/cn/java/j-lo-forkjoin/。[4] Coin 项目主页:http://wikis.sun.com/display/ProjectCoin/Home。[5] Lambda 项目主页:http://openjdk.java.net/projects/lambda/。1.5 实战:自己编译JDK

想要一探JDK内部的实现机制,最便捷的路径之一就是自己编译一套JDK。通过阅读和跟踪调试JDK源码去了解Java技术体系的原理,虽然门槛会高一点,但肯定会比阅读各种文章、书籍更加容易贴近本质。另外,JDK中的很多底层方法都是Native的,当需要跟踪这些方法的运作或对JDK进行Hack的时候,都需要编译一套自己的JDK。

现在网络上有不少开源的JDK实现可供选择,如Apache Harmony、OpenJDK等。考虑到Sun系列的JDK是现在使用得最广泛的JDK版本,本书选择了OpenJDK进行这次编译实战。1.5.1 获取JDK源码

首先确定要使用的JDK版本,OpenJDK 6和OpenJDK 7都是开源的,源码都可以在它们的主页(http://openjdk.java.net/)上找到,OpenJDK 6的源码其实是从OpenJDK 7的某个基线中引出的,然后剥离掉JDK 1.7相关的代码,从而得到一份可以通过TCK 6的JDK 1.6实现,因此直接编译OpenJDK 7会更加“原汁原味”一些,其实这两个版本的编译过程差异并不大。

获取源码有两种方式:一种是通过Mercurial代码版本管理工具从Repository中直接取得源码(Repository地址:http://download.java.net/openjdk/jdk7/)取得打包好的源码,一般来说大概一个月左右会更新一次,虽然不够及时,但的确方便了许多。笔者下载的是OpenJDK 7Early Access Source Build b121版,2010年12月9日发布的,大概81.7MB,解压后约308MB。1.5.2 系统需求

如果可能,笔者建议尽量在Linux或Solaris上构建OpenJDK,这要比在Windows平台上轻松许多,而且网上能找到的资料绝大部分都是在Linux上编译的。如果一定要在Windows平台上编译,建议认真阅读一下源码中的README-builds.html文档(无论是在OpenJDK网站上,还是在下载的源码包里面都有这份文档),因为编译过程中需要[1]注意的细节非常多。虽然不至于像文档上所描述的那么夸张,但是如果大家是第一次编译,在上面耗费一整天乃至更多的时间都很正常。

本书在本次实战中演示的是在32位Windows 7平台下编译x86版的OpenJDK(也就是32位的JDK),如果需要编译x64版,那毫无疑问也需要一个64位的操作系统。另外,编译涉及的所有文件都必须存放在NTFS格式的文件系统中,因为FAT32格式无法支持大小写敏感的文件名。在官方文档上写道:编译至少需要512MB的内存和600MB的磁盘空间。如果大家耐心很好的话,512MB的内存基本上也可以凑合使用,不过600MB的磁盘空间仅仅是指存放OpenJDK源码和相关依赖项的空间,要完成编译,600MB肯定是无论如何都不够的,这次实战中所下载的工具、依赖项、源码,全部安装和解压完成最少(最少是指只下载C++编译器,不下载VS的IDE)需要超过1GB的空间。

对系统的最后一点要求就是所有的文件,包括源码和依赖项目,都不要放在包含中文或空格的目录里面,这样做不是一定不可以,只是这样会为后续建立CYGWIN环境带来很多额外的工作,这是由于Linux和Windows的磁盘路径存在差别,我们也没有必要自己给自己找麻烦。1.5.3 构建编译环境[2]

准备编译环境的第一步是安装一个CYGWIN。这是一个在Windows平台下模拟Linux运行环境的软件,提供了一系列的Linux命令支持。需要CYGWIN的原因是因为在编译中要使用GNU Make来执行Makefile文件(C/C++程序员肯定很熟悉,如果只使用Java,把它当做C++版本的ANT看待就可以了)。安装CYGWIN时不能直接采用默认安装方式,因为表1-2中所示的工具在默认情况下都不会安装,但又是编译过程中需要的,因此要在图1-6的安装界面中进行手工选择。表1-2 需要手工选择安装的CYGWIN工具

CYGWIN安装时的定制包选择界面如图1-6所示。图1-6 CYGWIN安装界面

建立编译环境的第二步是安装编译器。JDK中最核心的代码(Java虚拟机及JDK中Native方法的实现等)是使用C++语言及少量的C语言编写的,官方文档中说它们的内部开发环境是在Microsoft Visual Studio C++2003(VS2003)中进行编译的,同时也在Microsoft Visual Studio C++2010(VS2010)中测试过,所以最好只选择这两个编译器中的一个进行编译。如果选择VS2010,那么在编译器之中已经包含了Windows SDK v 7.0a,否则可能还要自己去下载这个SDK,并且更新PlatformSDK目录。由于笔者没有购买Visual Studio 2010的IDE,所以仅仅下载了VS2010Express中提取出来的C++编译器,这部分是免费的,但单独安装好编译器比较麻烦,建议读者选择使用整套Visual Studio C++2010或Visual Studio C++2010Express版进行编译。

注意 CYGWIN和VS2010安装之后都会在操作系统的PATH环境变量中写入自己的bin目录路径,必须检查并保证VS2010的bin目录一定要在CYGWIN的bin目录之前,因为这两个软件的bin目录之中各自都有个连接器“link.exe”,但是只有VS2010中的连接器可以完成OpenJDK的编译。

准备JDK编译环境的第三步是下载一个已经编译好的JDK。这听起来也许有点滑稽——要用鸡蛋孵小鸡还真得先养一只母鸡呀?但仔细想想其实这个步骤很合理:因为JDK包含的各个部分(HotSpot、JDK API、JAXWS、JAXP……)有的是使用C++编写的,而更多的代码则是使用Java自身实现的,因此编译这些Java代码需要用到一个可用的JDK,官方称这个JDK为“Bootstrap JDK”。如果编译OpenJDK 7,Bootstrap JDK必须使用JDK6Update 14或之后的版本,笔者选用的是JDK6Update 21。

最后一个步骤是下载一个Apache ANT,JDK中的Java代码部分都是使用ANT脚本进行编译的,ANT版本要求在1.6.5以上,这部分是Java的基础知识,对本书的读者来说应该没有难度,笔者就不再详述。1.5.4 准备依赖项

前面说过,OpenJDK中开放的源码并没有达到100%,还有极少量的无法开源的产权代码存在。OpenJDK承诺日后将逐步使用开源实现来替换掉这部分产权代码,但至少在今天,编译JDK还需要这部[3]分闭源包,官方称之为“JDK Plug”,它们从前面的Source Releases页面就可以下载到。在Windows平台下的JDK Plug是以Jar包的形式提供的,通过下面这条命令可以安装它:java -jar jdk-7-ea-plug-b121-windows-i586-09_dec_2010.jar

运行后将会显示如图1-7所示的协议,点击ACCEPT接受协议,然后把Plug安装到指定目录即可。安装完毕后建立一个环境变量“ALT_BINARY_PLUGS_PATH”,变量值为此JDK Plug的安装路径,后面编译程序时需要用到它。

除了要用到JDK Plug外,编译时还需要引用JDK的运行时包,它是编译JDK中用Java代码编写的那部分所需要的,如果仅仅是想编译一个HotSpot虚拟机,则可以不用。官方文档把这部分称之为“Optional Import JDK”,可以直接使用前面的Bootstrap JDK的运行时包,我们需要建立一个名为“ALT_JDK_IMPORT_PATH”的环境变量指向JDK的安装目录。[4]

第三步是安装一个大于2.3版的FreeType,这是一个免费的字体渲染库,JDK的Swing部分和JConsole这类工具要使用到它。安装好后建立两个环境变量“ALT_FREETYPE_LIB_PATH”和“ALT_FREETYPE_HEADERS_PATH”,分别指向FreeType安装目录下的bin目录和include目录。另外,还有一点官方文档没有提到但必须要做的事情是把FreeType的bin目录加入到PATH环境变量中。图1-7 JDK Plug安装协议

第四步是下载Microsoft DirectX 9.0SDK(Summer 2004),安装后大约有298MB,在微软官方网站上搜索一下就可以找到下载地址,它是免费的。安装后建立环境变量“ALT_DXSDK_PATH”指向DirectX 9.0SDK的安装目录。

第五步是去寻找一个名为“MSVCR100.DLL”的动态链接库,如果读者在前面安装了全套的Visual Studio 2010,那这个文件在本机就能找到,否则上网搜索一下也能找到单独的下载地址,大概有744KB。建立环境变量“ALT_MSVCRNN_DLL_PATH”指向这个文件所在的目录。如果读者选择的是VS2003,这个文件名应当为“MSVCR73.DLL”。很多软件中都包含有这个文件,如果找不到,前面下载的“Bootstrap JDK”的bin目录中应该也有一个,直接拿来用吧。1.5.5 进行编译

现在,需要下载的编译环境和依赖项目都准备齐全了,最后我们还需要对系统进行一些设置以便编译能够顺利通过。

首先执行VS2010中的VCVARS32.BAT,这个批处理文件的主要目的是设置INCLUDE、LIB和PATH这几个环境变量。如果大家和笔者一样只是下载了编译器,则需要手工设置它们,各个环境变量的设置值可以参考代码清单1-1中的内容。批处理运行完之后建立“ALT_COMPILER_PATH”环境变量,让Makefile知道在哪里可以找到编译器。

再建立“ALT_BOOTDIR”和“ALT_JDK_IMPORT_PATH”两个环境变量,指向前面提到的JDK 1.6的安装目录,建立“ANT_HOME”指向Apache ANT的安装目录。建立的环境变量很多,为了避免遗漏,笔者写了一个批处理文件以供读者参考,如代码清单1-1所示。

代码清单1-1 环境变量设置SET ALT_BOOTDIR=D:/_DevSpace/JDK 1.6.0_21

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载