一、Java概述
1. Java受欢迎的原因
- 结构严谨、面向对象
- 摆脱硬件平台束缚,“一次编译,到处运行”
- 相对安全的内存管理和访问机制,避免了大部分的内存泄露和指针越界问题
- 热点代码检测和运行时编译及优化
- 完善的应用程序接口,还有无数来自商业机构和开源社区的第三方类库帮助用户实现各种各样的功能
2. JDK VS JRE
按照Java各组成部分的功能来划分,可以分为JRE和JDK
-
JDK(Java Development Kit):Java程序设计语言、Java虚拟机、Java类库。是
用于支持Java程序开发的最小环境
-
JRE(Java Runtime Environment):Java虚拟机和Java类库API中的Java SE API子集,是
支持Java程序运行的标准环境
。
3. Java Card、Java ME、Java SE、Java EE
按照技术所服务的领域或者按照技术关注的重点业务来划分,Java可以分为四个产品线:
- Java Card:支持Java小程序(Applets)运行在小内存设备(如智能卡)上的平台
- Java ME(Micro Edition):支持Java程序运行在移动终端(如手机、PDA)上的平台。在JDK 6以前被称为J2ME。注意:使用Java语言开发程序的Adriod并不属于J2ME
- Java SE(Standard Edition):支持面向桌面级应用(如Windows下的应用程序)的Java平台。在JDK 6以前被称为J2SE
- Java EE(Enterprise Edition):支持使用多层架构的企业应用(如ERP、MIS、CRM)的Java平台。在JDK 6以前被称为J2EE。在JDK 10之后被Oracle放弃,被捐献给Eclipse基金会管理,之后被称为Jakarta EE
二、JDK的发展史
1. Oak
1991年4月,有James Gosling博士领导的绿色计划启动,该计划的产品就是
Java语言的前身:Oak
(得名于James Gosling博士办公室前的一棵橡树)
1995年5月23日,Oak改名为Java,并在Sun World大会上正式发布Java 1.0版本,并正式提出”Write Once, Run Anywhere”。
2. JDK 1.0
1996年1月23日,JDK 1.0发布,该版本提供了一个纯解释执行的Java虚拟机(
Sun Classic VM
)实现。JDK 1.0版本的代表技术包括:Java虚拟机、Applet、AWT等。
1996年5月底,Sun公司于美国旧金山举办了
首届JavaOne大会
,从此JavaOne称为全世界数百万Java语言开发者每年一度的技术盛会。
3. JDK 1.1
1997年2月19日,Sun公司发布JDK 1.1,该版本的技术代表有:JAR文件格式、JDBC、JavaBeans、RMI等。
Java的语言得到一定增强,如
内部类、反射
等
直到1994年4月8日,JDK 1.1一共发布了1.1.0到1.1.8这9个版本,并且从1.1.4之后,每个版本都有一个工程代号。
4. JDK 1.2
1998年12月4日,JDK迎来一个里程碑的重要版本:JDK 1.2,代号PlayGroud(竞技场)。Sun公司在该版本
将Java体系拆分为J2SE、J2EE和J2ME
。该版本的代表技术有:EJB、Java Plug-in、Java IDL、Swing等。
Java第一次内置了JIT(Just In Time)即时编译器,并同时存在三个虚拟机:
Classic VM、HotSpot VM和Exact VM
,后两款虚拟机内置JIT,而Classic VM需要以外挂形式使用JIT。
在语言层面上,增加了stricftp关键字,Java类库添加了Collections集合类等。
1994年4月27日,Longview Technologiea公司开发了HotSot VM,由于该虚拟机的卓越性能,1997年Sun公司收购该公司,并提供JDK 1.2使用HotSot VM,在JDK 1.3版及之后,HotSot VM成为JDK的默认虚拟机。
5. JDK 1.3
2000年5月,代号Kestrel(美洲红隼)的JDK 1.3版本发布。该版本的改进主要体现在Java类库上(如数学运算、新的Timer API等)。该版本还对Java 2D做了很多改进,提供了大量的Java 2D API,并添加了JavaSound类库。
从JDK 1.3之后开始,Sun公司大约
每隔两年发布一个JDK的主版本,并以动物命名,期间发布的各个修正版本则是以昆虫作为代号
6. JDK 1.4
2002年2月13日,JDK 1.4版本发布,代号Merlin(灰背隼),该版本标志着
Java真正走向成熟
。该本的的新技术特性包括:
正则表达式、异常链、NIO、日志类、XML解析器和XSLT转换器
等。
2002年前后,微软.NET FrameWork发布,该技术平台与Java在技术实现和目标用户上有着很多相似之处,直至今日,两个平台之间孰优孰劣的争执还没有平息。
7. JDK 5
2004年9月30日,JDK 5发布,工程代号Tiger。从该版本开始,Sun公司放弃了”JDK 1.x”的命名方法,采用”JDK x”命名版本号。
该版本在语法易用性上做出了非常大的改进,如:
自动装箱、泛型、动态注解、枚举、可变长参数、遍历循环(foreach循环)等
。
虚拟机和API层面上,该版本改进了Java的内存模型(Java Memory Model, JMM),提供了java.util.concurrent并发包。
8. JDK 6
2006年12月11日,JDK 6发布,代号Mustang(野马)。Sun公司从该版本开始,放弃了J2EE、J2SE、J2ME的产品线命名方式,改用
Java EE6、Java SE6、Java ME6
的命名方式。
该版本的改进包括:提供初步的动态语言支持(通过内置的Mozilla JavaScript Rhino引擎实现)、提供编译期注解处理器和微型HTTP服务器API等。
2006年11月13日,在JavaOne大会上,Sun公司宣布Java开源
。随后的一年多时间内,Sun公司陆续将JDK的各部分在GPL v2(GNU General Public License v2)协议下公开了源码,并建立了OpenJDK组织对这些源码进行独立管理。
OpenJDK几乎拥有了当时SunJDK 7的所有源码,在JDK 7中,OpenJDK和SunJDK除了代码头文件的版权注释外,代码几乎是完全一样的。
JDK 6之后,由于代码复杂度、Java开源、开发JavaFX、世界经济危机以及Oracle对Sun的收购案等原因,JDK的更新没有维持两年更新一个版本的研发速度。
JDK 6的生命周期异常顽强,一共发布了211个更新升级补丁。
9. JDK 7
2009年2月19日,工程代号dolphin的JDK 7完成第一个里程碑版本,按照最初的设计,Sun公司一共设置了十个里程碑,最后一个里程碑版本原定于2010年9月9日结束。但是由于种种原因,JDK 7最终无法按照计划完成。
JDK 7开发期间,
Sun公司在技术竞争和商业竞争中陷入泥潭
,股价仅有高峰时期的3%,无力推进JDK 7的研发计划。
Oracle收购Sun公司后随即实行B计划,大幅裁剪JDK 7的预期目标
,以保证JDK 7正式版本能够于2011年7月28日准时发布。
JDK 7的最终改进有:提供新的G1收集器(在发布时仍处于Experimental状态,直到2012年4月的Update 4中才正式商用)、加强对非Java语言的调用支持、可并行的累加器架构等。
Oracle接收Sun之后,针对广泛使用而又免费的Java SE产品线,定义了一套新的Java SE Support产品计划,将JDK的更新作为一项商业服务。JDK 7发布之前的80个更新仍然免费面向所有用户提供,之后的更新包,用户只能从”将Java SE升级到Java SE Support”和”将JDK升级到更高版本”两个选项中选一个。
JDK 7 Update6之后,官方提供的JDK可以运行于Windows、Linux、Solaris和Mac OS X操作系统上,支持ARM、x86、x86-64和SPAC指令集架构。
10. JDK 8
2009年4月20日,Oracle正式宣布以74亿美元的价格收购市值曾经高达2000亿美金的Sun公司
。在这之前,Oracle还收购了另一家大型的中间件企业BEA。从此之后,
Oracle拥有了世界三大商用虚拟机的其中两个:JRockit和HotSpot。
JDK 8的第一个正式版本原定于2013年9月份发布,最终还是跳票到了2014年3月18日。JDK 8提供了曾经在JDK 7中规划过的功能,包括:
-
JEP126:
对Lambda表达式的支持,这让Java拥有了流畅的函数式表达能力
- JEP104:内置Nashorn JavaScript引擎的支持
- JEP105:新的时间、日期API
-
JEP122:
彻底移除HotSpot的永久代
原定于JDK 8中提供的Jigsaw功能(虚拟机层面的模块化支持)再次被延期到JDK 9中
11. JDK 9
JDK 9原定于2016年发布,但在2016年伊始,Oracle又宣布JDK 9要延期到2017年,后面经过两次短时间的跳票之后,最终到2017年9月21日才得以艰难面世。
之所以跳票如此之久,原因在于Oracle与以IBM、RedHat为首的十三家企业有关Java模块化规范的争执。Oracle提出以Jigsaw作为Java模块化规范进入JDK 9的发布范围,而IBM自家的JDK实现了高度的模块化,还带头成立了OSGi联盟,制定了Java框架层面模块化的事实标准,IBM更希望将OSGi推进到Java规范中。
经过多番的斗争与妥协,JDK 9最终还是带着Jigsaw发布。
除了Jigsaw,JDK 9还增强了若干工具,包括:JS Shell、JLink、JHSDB等,同时整顿了HotSpot各个模块各自为战的日志系统,支持了HTTP2客户端API。
JDK 9之后,Oracle宣布Java将以持续交付的形式和更加敏捷的研发节奏推进,之后
JDK将会在每年的3月和6月个发布一个大版本
。同时,为了减少运维成本,Oracle放弃了”每个JDK版本最少维护三年”的传统,从此之后,
每六个JDK大版本中才会被划出一个长期支持(Long Term Support, LTS)版,只有LTS版的JDK才会获得为期三年的支持和更新,而普通JDK只有六个月的生命周期
。JDK 8和JDK 11会是LTS版,接着就是2021年发布的JDK 17。
12. JDK 10
2018年3月20日,JDK 10发布,该版本的研发目标在于内部重构,包括:统一源仓库、统一垃圾回收器接口、统一即时编译器接口等。对于用户而言,JDK 10的新特性显得乏善可陈。
2018年3月27日,Andriod的Java侵权案有了最终判决,
法院裁定Google赔偿Oracle合计88亿美元
。考虑到2009年Oracle只以74亿美金收购Sun公司,Oracle彻底”白嫖”了Sun公司。Andriod刚起步时,是Sun公司主动向Google抛去橄榄枝,而Andriod的流行也巩固了Java”行业第一编程语言”的行业地位。而Oracle在收购Sun之后反手状告Google,不得不说有些”不厚道”。
2018年3月,Oracle正式宣告放弃Java EE
,虽然Java EE也曾经无比辉煌,但是Oracle仍然将其”扫地出门”,最终赠送给Eclipse基金会,唯一条件是以后不允许使用”Java”商标,取而代之的是Jakarta EE。
2018年10月,JavaOne 2018在旧金山举行,这也是最后一届JavaOne大会
。JavaOne成为Oracle下一个裁撤对象。同年,Java Mission Control的开发团队也被Oracle解散。
13. JDK 11
2018年9月25日,JDK 11发布。该版本的改进包括:
ZGC垃圾回收器、将JDK 10的类型判断加入Lambda语法
。但是最重要的是,同时爆出谣言”Java要开始收费了”。
随着JDK 11发布,Oracle调整了JDK的授权许可证。首先,Oracle从JDK 11开始,把之前的商业特性全部开源给OpenJDK,这样OpenJDK 11和Oracle 11的代码和功能本质上完全相同;然后,Oracle宣布以后会
同时发布两个JDK:一个是以GPL v2+CE协议下由Oracle发型的OpenJDK,一个是在新的OTN协议下发行的传统的Oracle JDK
,这两个JDK共享大部分的源码,功能上基本一样;最后,Oracle JDK个人仍然可以免费使用,但是在生产环境商业需要付费,可以有三年的更新支持。
2019年2月,RedHat同时从Oracle手上接过OpenJDK 8和OpenJDK 11的管理权限和维护职责,
RedHat代替Oracle成为JDK历史版本的维护者
。
14. JDK 12
2019年3月20日,JDK 12发布,该版本的改进在于:Switch表达式、Java微测试套件(JMH)等。
该版本最大的特性,在于
引入了由RedHat领导开发的Shenandoah垃圾回收器
。由于Shenandoah是首个非Oracle开发的垃圾回收器,Oracle在OracleJDK 12中对Shenandoah进行了抵制,通过条件编译,强制将Shenandoah的代码进行剔除。从此,Shenandoah成为历史上唯一进入OpenJDK发布清单,而在OracleJDK中无法使用的功能。
三、常见JVM虚拟机
1. Sun Classic/Exact VM
Sun Classic 虚拟机是”世界上第一款商业虚拟机”
。早在JDK 1.0时,该版本所使用的虚拟机就是Classic 虚拟机。
Classic 虚拟机只能使用纯解释器方式执行Java代码。如果要使用即使编译器,就必须进行外挂,但是一旦外挂了即时编译器,即时编译器就会完全接管虚拟机的执行系统。
由于解释器和编译器不能配合工作,这就意味着要使用编译执行,编译器就不得不对每一个方法、每一行代码都进行编译,无论他们执行的频率是否具有编译的价值。因此即使采用了即使编译,执行效率也很低。
在JDK 1.2时,在Solaris平台上发布过一款名为Exact VM的虚拟机,它的编译系统已经具备现代高性能虚拟机雏形,如:热点探测、两级即时编译、编译器与解释器混合工作模式等。
Exact VM采用了准确式内存管理
(Exact Memory Management,也可以叫做Non-Conservative/Accurate Memory Managment)。所谓准确式内存管理就是虚拟机可以知道内存中某个位置的数据到底是什么类型,如内存中有一个32bit的123456,虚拟机可以知道它到底是一个指向了123456的内存地址的引用类型,还是一个数值为123456的整数。基于准确式内存管理,
Exact VM可以抛弃以前Classic VM基于句柄的对象查找方式
,这样每次定位对象都少了一次间接查找的开销,显著提升执行性能。
Exact VM只在商用应用上存在了很短的一段时间,之后就被HotSpot VM所取代。而Classic VM的生命周期更长,在JDK 1.2之前,它是JDK中唯一的虚拟机,在JDK 1.2时与HotSpot VM并存,但是默认还是使用Classic VM。在JDK 1.3时,HotSpot VM成为默认虚拟机,而Classic VM任然还是虚拟机的”备用选择”。直到JDK 1.4才退出历史舞台。
2. HotSpot VM
HotSpot VM是Sun/OracleJDK和OpenJDK中的默认虚拟机,也是
目前使用范围最广的Java虚拟机
。但是HotSpot VM最初并非由Sun公司开发,而是
由一家小公司Longview Technologies设计
,直到1997年Sun公司收购Longview Technologies,才获得了HotSpot VM。
HotSpot VM继承了之前的两款虚拟机的优点。但是,其实HotSpot VM和Exact VM基本上是同时期的产品,甚至HotSpot VM出现的还稍早一点。而且HotSpot VM采用了和Exact VM一样的
准确式内存管理
。为了HotSpot VM和Exact VM哪一个成为Sun主要支持的虚拟机,Sun公司内部还争吵过一番,而HotSpot VM击败Exact VM不能算得上技术上的胜利。
HotSpot VM也有和Exact VM一样的
热点代码探测能力
。通过执行计数器找出最具有编译价值的代码,然后通知即时编译器以方法为单位进行编译。如果一个方法被频繁调用或者方法中有效循环次数很多,将会分别触发标准及时编译和栈上替换编译。通过解释器和编译器的协调工作,可以在最优化的程序响应时间和最佳执行性能中取得平衡。
2006年,Sun公司开源SunJDK,形成了OpenJDK项目,HotSpot虚拟机成为Sun/OracleJDK和OpenJDK共同的虚拟机。Oracle收购Sun之后,建立了HotRockit项目,将BEA JRocket中的优秀特性加入HotSpot VM,2014年的JDK 8中,HotSpot VM已经融合了JRockit的特性,
移除掉了永久代,并加入了JRocket的Java Mission Control监控工具
。
3. Mobile / Embedded VM
Java在移动端和嵌入式市场,也有专门的虚拟机产品。
Oracle在Java ME产品线上的虚拟机命名为CDC-HI VM和CLDC-HI VM
。
Java ME中的Java虚拟机现在处于较为尴尬的位置,它最大的一块市场–智能手机已经被Andriod和IOS二分天下。
而在嵌入式设备上,Java ME Embedded又面临自家Java SE Embedded的直接竞争和侵蚀。Java SE Embedded带的Java虚拟机还是HotSpot,但这是为了适应嵌入式开发环境专门定制裁剪的版本,尽可能在支持完整的Java SE功能的前提下向着减少内存消耗的方向优化。
面向更低端设备的CLDC-HI仍在智能控制器、传感器等领域有着自己的一片市场,但是前途也不容乐观。在CLDC-HI中活的最好的反而是本该被淘汰的KVM,国内的老人机和出口到经济欠发达国家的功能手机还在使用KVM。
4. BEA JRockit / IBM J9 VM
HotSpot VM、JRockit VM和J9 VM曾经并称为”三大商业Java虚拟机”。
JRockit 虚拟机是一款专门为服务器硬件和服务端应用场景高度优化的虚拟机
,由于专注于服务端应用,它可以不太关注程序启动速度,因此JRockit 内部不包含解释器实现,全部代码都靠即使编译器编译后执行。JRockit 虚拟机的垃圾回收器和Java Mission Control故障处理套件等在当时也处于领先地位。随着BEA被Oracle收购,JRockit 虚拟机不在继续发展,永远停留在了R28版本。
J9 虚拟机与JRockit 虚拟机不一样,它的市场定位与HotSpot接近,是
一款在设计上全面考虑服务端、桌面应用,再到嵌入式的多用途虚拟机
。
J9 虚拟机的职责分离与模块化做得比HotSpot更为优秀
。由J9 虚拟机中抽象封装出来的核心组件(包括垃圾回收器、即时编译器、诊断监控子系统等)就单独构成了IBM OMR项目。
2016年起,IBM逐步将OMR项目和J9 虚拟机进行开源,完全开源后将它们捐献给了Eclipse基金会管理,并重新命名为Eclipse OMR和OpenJ9
。
5. BEA Liquid VM / Azul VM
这两个虚拟机是一类与特定硬件平台绑定、软硬件配合工作的专有虚拟机,这类虚拟机能够实现更高的执行性能,或者提供某些特殊的功能特性。
Liquid VM又被称为JRockit VE(Virtual Edition),由BEA公司开发
,可以直接运行在自家Hypervisor系统上的JRockit 虚拟机的虚拟化版本。Liquid VM不需要操作系统、网络支持等,或者说它
自己本身实现了一个专用操作系统的必要功能
,包括线程调度、文件系统、网络支持等,可以最大程度发挥硬件的能力。
随着JRockit 虚拟机终止开发,Liquid VM项目也已经终止
。
Azul VM是由Azul System公司在HotSpot的基础上进行大量改造
,运行于Azul System公司的专有硬件Vega系统上的Java虚拟机。该款虚拟机可以管理至少数十个CPU和数百GB的内存,并提供了在巨大内存范围内停顿时间可控的垃圾回收器(
大名鼎鼎的PGC和C4收集器
)。2010年,Azul公司重心开始逐渐从硬件转向软件,发布了
Zing虚拟机
,并最终放弃了Vega产品线,将全部精力投入Zing和Zulu产品线。
Zing 虚拟机是一个在HotSpot某旧版本代码分支基础上独立出来重新开发的高性能Java虚拟机
,可以运行在通用的Linux/x86平台上。
Zing的PGC和C4收集器可以轻易支持TB级别的Java堆内存,同时保证暂停时间仍然可以维持在不超过10毫秒的范围内
。HotSpot虚拟机直到JDK 11和JDK 12的ZGC以及Shenandoah收集器才达到了相同的目标,而且目前的效果仍然远不如C4。
6. Apache Harmony / Google Andriod Dalvik VM
Harmony 虚拟机(准确的说是Harmony里的DRLVM)和Dalvik虚拟机只能称为
虚拟机
,而不能被称为
Java虚拟机
。
Apache Harmony是一个Apache基金会旗下以Apache License协议开源的实际兼容于JDK 5和JDK 6的Java程序运行平台,它有自己的虚拟机和Java类库API
。但是,它
没有通过TCK认证
。如果一个公司宣称自己的平台”兼容于Java技术体系”,那该运行平台就要通过TCK(Technology Compatibality Kit)的兼容性认证。Apache基金会因为TCK授权的问题,先后与Sun以及收购Sun的Oracle公司产生了不可开交的矛盾,最终Apache基金会愤然退出JCP组织。而
随着JDK开源形成OpenJDK之后,Apache Harmony开源的优势也被极大抵消
,以至于该项目的最大参与者IBM公司也宣布辞去Harmony项目的管理主席,转而参与OpenJDK的开发。但是,
Apache Harmony项目的很多代码还是被吸纳进了IDM的JDK 7实现以及Google Andriod SDK之中
。
Dalvik 虚拟机曾经是Andriod平台的核心组成部分之一,它没有遵循《Java虚拟机规范》,不能直接指向Java的Class文件,同时它使用的是寄存器架构而不是Java虚拟机中常见的栈架构。在Andriod发展的早期,Dalvik 虚拟机随着Andriod的成功迅速流行。在Andriod 2.2中开始提供即时编译器实现,执行效率进一步提高。但在Andriod 4.4中出现了支持提前编译(Ahead of Time Compilation, AOT)的ART虚拟机,并全面代替了Dalvik 虚拟机。
7. Microsoft JVM以及其他
Microsoft JVM是微软为了在Internet Explorer 3浏览器中支持Java Applets应用而开发的Java虚拟机
,这款虚拟机只有Windows平台的版本,但却是
当时Windows系统下性能最好的Java虚拟机
。
但是,1997年,Sun公司以侵犯商标、不正当竞争等罪名状告微软,并最终裁决微软向Sun公司(最终微软因垄断赔偿给Sun公司的总金额高达10亿美金)赔偿2000万美元,并承诺终止其Java虚拟机的发展。
令人讽刺的是。当
Windows XP SP3中的Java虚拟机被完全移除
后,Sun公司又到处登报希望微软不要这样做。试想一下,如果当时Sun公司没有起诉微软,微软继续保持着对Java技术的热情,是否Java的世界会变得更好?.Net技术是否还会发展起来?