深入理解JVM:走近Java

来自Wikioe
跳到导航 跳到搜索


Java技术体系

  • 从广义上讲,Kotlin、Clojure、JRuby、Groovy等运行于Java虚拟机上的编程语言及其相关的程序都属于Java技术体系中的一员。

从传统意义上来看,JCP官方(Java Community Process,就是人们常说的“Java社区”)所定义的Java技术体系包括了以下几个组成部分:

  1. Java程序设计语言
  2. 各种硬件平台上的Java虚拟机实现
  3. Class文件格式
  4. Java类库API
  5. 来自商业机构和开源社区的第三方Java类库
  • JDK(Java Development Kit):Java程序设计语言、Java虚拟机、Java类库,三部分的统称,
    JDK是用于支持Java程序开发的最小环境
  • JRE(Java Runtime Environment):Java类库API中的Java SE API子集和Java虚拟机,两部分的统称,
    JRE是支持Java程序运行的标准环境。


Java技术体系所包括的内容.jpg


以Java技术体系划分为以下四条主要的产品线:

  1. Java Card:支持Java小程序(Applets)运行在小内存设备(如智能卡)上的平台。
  2. Java ME(Micro Edition):支持Java程序运行在移动终端(手机、PDA)上的平台,对Java API有所精简,在JDK 6以前被称为J2ME。
    Android 不属于Java ME !
  3. Java SE(Standard Edition):支持面向桌面级应用(如Windows下的应用程序)的Java平台,提供了完整的Java核心API,JDK 6以前被称为J2SE。
  4. Java EE(Enterprise Edition):支持使用多层架构的企业应用(如ERP、MIS、CRM应用)的Java平台,除了提供Java SE API外,还对其做了大量有针对性的扩充(javax.* 下),JDK 6以前被称为J2EE;
    在JDK 10以后被Oracle放弃,捐献给Eclipse基金会管理,此后被称为Jakarta EE。

Java发展史

  • 起源:由James Gosling博士领导的绿色计划(Green Project)开始启动,其产品就是Java语言的前身:Oak(得名于James Gosling办公室外的一棵橡树)。


Java技术发展的时间线.jpg


时间 JDK 版本 描述
1995年5月23日,Oak语言改名为Java,并且在SunWorld大会上正式发布Java 1.0版本。Java语言第一次提出了“Write Once,Run Anywhere”的口号。
1996年1月23日 1.0 第一个正式版本的运行环境。JDK 1.0提供了一个纯解释执行的Java虚拟机实现(Sun Classic VM)。
  • 代表技术:Java虚拟机、Applet
1997年2月19日 1.1 Java里许多最基础的技术支撑点(如JDBC等)都是在JDK 1.1版本中提出的。
  • Java的语法增强:内部类(Inner Class)反射(Reflection)都是在这时候出现的。
  • 代表技术:JAR文件格式、JDBC、JavaBeans、RMI等
1998年12月4日 1.2(layground竞技场) Java技术体系被拆分为三个方向:J2SEJ2EEJ2ME
  • Java虚拟机第一次内置了JIT即时编译器(Just InTime)
    (JDK 1.2中曾并存过三个虚拟机,“Classic VM”、“HotSpot VM”和“Exact VM”
    其中Exact VM只在Solaris平台出现过;后面两款虚拟机都是内置了JIT即时编译器的,而之前版本所带的Classic VM只能以外挂的形式使用即时编译器。
  • 在语言和API层面上,Java添加了strictfp关键字,Java类库添加了现在Java编码之中极为常用的一系列Collections集合类等。
  • 代表技术:EJB、Java Plug-in、Java IDL、Swing等
1999年4月27日,HotSpot虚拟机诞生:发布时是作为JDK 1.2的附加程序提供的,后来它成为JDK 1.3及之后所有JDK版本的默认Java虚拟机。
2000年5月8日 1.3(美洲红隼Kestrel) 改进了主要体现在Java类库上(如数学运算和新的Timer API等),* JNDI服务从JDK 1.3开始被作为一项平台级服务提供(以前JNDI仅仅是一项扩展服务),使用CORBA IIOP来实现RMI的通信协议,等等。这个版本还对Java 2D做了很多改进,提供了大量新的Java 2D API,并且新添加了JavaSound类库
  • 修正版本:1.3.1(瓢虫Ladybird)
2002年2月13日 1.4(灰背隼Merlin) JDK 1.4是标志着Java真正走向成熟的一个版本。
  • JDK 1.4同样带来了很多新的技术特性,如正则表达式异常链NIO日志类XML解析器XSLT转换器等等。
  • 修正版本:1.4.1(蚱蜢Grasshopper)1.4.2(螳螂Mantis)
2002年前后,微软的.NET Framework发布。
2004年9月30日 5(老虎Tiger) 将产品版本号修改成了“JDK x”。
  • Java语法易用性上做出了非常大的改进,如:自动装箱泛型动态注解枚举可变长参数、遍历循环(foreach循环)等语法特性都是在JDK 5中加入的。
  • 在虚拟机和API层面上,这个版本改进了Java的内存模型(Java Memory Model,JMM)、提供了java.util.concurrent并发包等。
2006年12月11日 6(野马Mustang) Sun公司终结了J2EE、J2SE、J2ME的产品线命名方式,启用Java EE 6、Java SE 6、JavaME 6的新命名来代替。
  • JDK 6的改进包括:提供初步的动态语言支持(通过内置Mozilla JavaScriptRhino引擎实现)、提供编译期注解处理器微型HTTP服务器API,等等。
  • 同时,这个版本对Java虚拟机内部做了大量改进,包括锁与同步垃圾收集类加载等方面的实现都有相当多的改动。
2006年11月13日,Java开源:Sun公司将JDK在“GPL v2”协议下公开了源码,并建立了“OpenJDK”组织对源码进行独立管理。
2009年2月19日 7 (海豚Dolphin) 按照JDK 7最初的功能规划,一共会设置十个里程碑。最后一个里程碑版本原计划定于2010年9月9日结束,但由于各种原因,JDK 7最终无法按计划完成。
  • 从JDK 7最原始的功能清单(Oracle收购Sun公司后裁剪了预定目标):
    1. Lambda项目:支持Lambda表达式,支持函数式编程。(未完成)
    2. Jigsaw项目:虚拟机层面的模块化支持。(未完成)
    3. 动态语言支持:Java是静态语言,为其他运行在Java虚拟机上的动态语言提供支持。
    4. Garbage-First收集器。
    5. Coin项目:Java语法细节进化。(未完成)
    最终,JDK 7包含的改进有:提供新的G1收集器(G1在发布时依然处于Experimental状态,直至2012年4月的Update 4中才正式商用)、加强对非Java语言的调用支持(JSR-292,这项特性在到JDK 11还有改动)、可并行的类加载架构等。
  • 扩展了系统支持:
    1. 支持“Windows”(不含Windows 9x)、“Linux、Solaris”和“Mac OS X”操作系统,
    2. 支持“ARM”、“x86”、“x86-64”和“SPARC”指令集架构
    (JDK 7是支持Windows XP的最后一个版本)。
2009年4月20日,Oracle收购Sun公司,并分别从BEA和Sun手中取得了世界三大商用虚拟机的其中两个:“JRockit”和“HotSpot”。
2014年3月18日 8 从JDK 8开始,Oracle启用JEP(JDK Enhancement Proposals)来定义和管理纳入新版JDK发布范围的功能特性。
  • 提供了未能在JDK 7中完成的功能,主要包括:
    1. JEP 126:对Lambda表达式的支持,这让Java语言拥有了流畅的函数式表达能力。
    2. JEP 104:内置Nashorn JavaScript引擎的支持。
    3. JEP 150:新的时间、日期API。
    4. JEP 122:彻底移除HotSpot的永久代
    5. ……
2017年9月21日 9 完成了7中预定的Jigsaw项目(虚拟机层面的模块化支持),增强了若干工具(JS Shell、JLink、JHSDB等),整顿了HotSpot各个模块各自为战的日志系统,支持HTTP 2客户单API等91个JEP。
2018年3月20日 10 这版本的主要研发目标是内部重构,诸如统一源仓库、统一垃圾收集器接口、统一即时编译器接口(JVMCI在JDK 9已经有了,这里是引入新的Graal即时编译器)等。
2018年3月,Oracle将Java EE所有权直接赠送给Eclipse基金会,并以“Jakarta EE”的名字存在。
2018年9月25日 11 这是一个LTS版本的JDK,包含17个JEP,其中有ZGC垃圾收集器这样的革命性的出现,也有把JDK 10中的类型推断加入Lambda语法这种可见的改进。
  • “Java要开始收费啦!”:Oracle调整了JDK的授权许可证,宣布以后将会同时发行两个JDK(二者共享绝大部分源码):
    1. 以GPLv2+CE协议下由Oracle发行的OpenJDK(OracleOpenJDK):可以免费在开发、测试或生产环境中使用,但是只有半年时间的更新支持;
    2. 在新的OTN协议下发行的传统的OracleJDK:个人依然可以免费使用,但若在生产环境中商用就必须付费,可以有三年时间的更新支持;
2019年2月,RedHat同时从Oracle手上接过OpenJDK 8和OpenJDK 11的管理权利和维护职责,成为JDK历史版本的维护者。
2019年3月20日 12 其中主要有Switch表达式、Java微测试套件(JMH)等新功能,最引人注目的特性无疑是加入了由RedHat领导开发的Shenandoah垃圾收集器
Shenandoah作为首个由非Oracle开发的垃圾收集器,其目标又与Oracle在JDK 11中发布的ZGC几乎完全一致,两者天生就存在竞争。Oracle马上用实际行动抵制了这个新收集器,在JDK 11发布时才说应尽可能保证OracleJDK和OpenJDK的兼容一致,转眼就在OracleJDK 12里把Shenandoah的代码通过条件编译强行剔除掉,使其成为历史上唯一进入了OpenJDK发布清单,但在OracleJDK中无法使用的功能。

Java虚拟机家族

从1996年初Sun发布的JDK 1.0中包含的Sun Classic虚拟机到今天,曾经涌现、湮灭过许多或经典,或优秀,或有特色,或有争议的虚拟机实现:

  • 但讨论最多的还是“HotSpot”;
虚拟机 描述
Sun Classic/Exact VM 虚拟机始祖
HotSpot VM 武林盟主:
  • OracleJDK和OpenJDK中的默认Java虚拟机
  • 准确式内存管理、热点代码探测技术
    准确式内存管理是指虚拟机可以知道内存中某个位置的数据具体是什么类型;
    热点代码探测能力可以通过执行计数器找出最具有编译价值的代码,然后通知即时编译器以方法为单位进行编译;
  • 的JDK 8时期,HotSpot实现了与JRockit的融合
    移除掉永久代;
    吸收了JRockit的Java Mission Control监控工具等
Mobile/Embedded VM 小家碧玉:
  • 应用于移动和嵌入式市场(JavaME 产品线)
  • 以前功能机的“KVM”就是其中之一
BEA JRockit/IBM J9 VM 天下第二:
  • JRockit随着BEA被Oracle收购,现已不再继续发展,永远停留在R28版本(JDK 6版JRockit的代号)。
    内部不包含解释器实现,全部代码都靠即时编译器编译后执行;
    其垃圾收集器和Java Mission Control故障处理套件等部分的实现,在当时众多的Java虚拟机中也处于领先水平。
  • IBM J9直至今天仍旧非常活跃:从2016年起逐步将OMR项目和J9虚拟机进行开源,完全开源后便将它们捐献给了Eclipse基金会管理,并重新命名为Eclipse OMR和OpenJ9
    如果为了学习虚拟机技术而去阅读源码,更加模块化的OpenJ9代码其实是比HotSpot更好的选择;
    职责分离与模块化做得比HotSpot更优秀,由J9虚拟机中抽象封装出来的核心组件库(包括垃圾收集器、即时编译器、诊断监控子系统等)就单独构成了IBM OMR项目,可以在其他语言平台如Ruby、Python中快速组装成相应的功能。
BEA Liquid VM/Azul VM 软硬合璧:
  • 与特定硬件平台绑定、软硬件配合工作的专有虚拟机
Apache Harmony/Google Android Dalvik VM 挑战者:
  • 只能称作“虚拟机”,而不能称作“Java虚拟机”;
Microsoft JVM 及其他 没有成功,但并非失败

展望Java技术的未来

无语言倾向

Graal VM被官方称为“Universal VM”和“Polyglot VM”,这是一个在HotSpot虚拟机基础上增强而成的跨语言全栈虚拟机,可以作为“任何语言”的运行平台使用。 Graal VM可以无额外开销地混合使用这些编程语言,支持不同语言中混用对方的接口和对象,也能够支持这些语言使用已经编写好的本地库文件。

Graal VM.jpg

Graal VM的基本工作原理是将这些语言的源代码(例如JavaScript)或源代码编译后的中间格式(例如LLVM字节码)通过解释器转换为能被Graal VM接受的中间表示(Intermediate Representation,IR),譬如设计一个解释器专门对LLVM输出的字节码进行转换来支持C和C++语言,这个过程称为程序特化(Specialized,也常被称为Partial Evaluation)。Graal VM提供了Truffle工具集来快速构建面向一种新语言的解释器,并用它构建了一个称为Sulong的高性能LLVM字节码解释器。

新一代即时编译器

HotSpot虚拟机中含有两个即时编译器,分别是“编译耗时短但输出代码优化程度较低的客户端编译器”(简称为C1)以及“编译耗时长但输出代码优化质量也更高的服务端编译器”(简称为C2),通常它们会在分层编译机制下与解释器互相配合来共同构成HotSpot虚拟机的执行子系统。


自JDK 10起,HotSpot中又加入了一个全新的即时编译器:Graal编译器(来自于“Graal VM”)。Graal编译器是以C2编译器替代者的身份登场的,能够做比C2更加复杂的优化,如“部分逃逸分析”(PartialEscapeAnalysis),也拥有比C2更容易使用激进预测性优化(Aggressive Speculative Optimization)的策略,支持自定义的预测性假设等。

向Native迈进

在微服务架构的视角下,应用拆分后,单个微服务很可能就不再需要面对数十、数百GB乃至TB的内存,有了高可用的服务集群,也无须追求单个服务要7×24小时不间断地运行,它们随时可以中断和更新;但Java明显相悖于这些特点。


Substrate VM是在Graal VM 0.20版本里新出现的一个极小型的运行时环境,包括了独立的异常处理、同步调度、线程管理、内存管理(垃圾收集)和JNI访问等组件,目标是代替HotSpot用来支持提前编译后的程序执行。Substrate VM补全了Graal VM“Run Programs Faster Anywhere”愿景蓝图里的最后一块拼图,让Graal VM支持其他语言时不会有重量级的运行负担。

灵活的胖子

HotSpot的定位是面向各种不同应用场景的全功能Java虚拟机,这是一个极高的要求,仿佛是让一个胖子能拥有敏捷的身手一样的矛盾。而随着HotSpot开发团队持续地重构着HotSpot的架构,HotSpot虚拟机正逐渐变得更佳灵活。

语言语法持续增强

实战:自己编译JDK

获取源码 系统需求 构建编译环境 进行编译 在IDE工具中进行源码调试

本章小结