我们都知道目前jdk默认用的是HotSpot虚拟机,那么为什么要用HotSpot虚拟机?除了他就没别的虚拟机了吗?虚拟机到底是怎么编译运行的?伴随着这些疑问,结合着【深入理解Java虚拟机】一书当中整理了本篇博客,感兴趣的可以跟着博主学习一下!
许多Java程序员都会潜意识地把Java虚拟机 与OracleJDK的HotSpot虚拟机等同看待,也许还有一些程序员会注意到BEA JRockit和IBM J9虚拟机, 但绝大多数人对Java虚拟机的认识就仅限于此了。从1996年初Sun发布的JDK 1.0中包含的Sun Classic虚 拟机到今天,曾经涌现、湮灭过许多或经典,或优秀,或有特色,或有争议的虚拟机实现,本篇文章主要回顾Java虚拟机家族的发展轨迹和历史变迁。
在进行阅读各种种类的虚拟机的时候,会发现一些名词根本不知道什么意思,例如解释器、编译器、jit等等。
做为Java开发人员,我们编写的代码是以“.java”为文件后缀的,也就是常说的源码。源码在经过javac命令编译之后,就会生成一个对应“.class”文件,这个就是字节码文件。它为Java的一次编译,到处运行提供了基础。通过JVM的映射,同一份字节码文件,可以在不同的系统上运行,这里就得益于JVM的内部处理了,即:通过JVM屏蔽了底层硬件的差异。但实际上字节码文件还不能算编译完成,它是一个“半成品”,通过JVM内部的处理,才能够转换成处理器能够识别的指令代码。
直白的理解就是,java之所以可以一次编写,到处运行,是将.java变成了.class文件,然后又依赖于不同服务器所对应不同的java虚拟机来进行对.class文件进行解析,将.class文件解析成计算机可直接识别的命令。
注意:.class文件就是我们一直所说的字节码文件
百度百科:解释器
(英语:Interpreter),又译为直译器,有的还叫转译器,是一种电脑程序,能够把高级编程语言一行一行直接转译运行
。解释器不会一次把整个程序转译出来,只像一位“中间人”,每次运行程序时都要先转成另一种语言再作运行,因此解释器的程序运行速度比较缓慢(这块指的就是.class文件需要转换成机器可识别的语言,机器可以是linux,也可以是windows等等)。它每转译一行程序叙述就立刻运行,然后再转译下一行,再运行,如此不停地进行下去。
Python、TCL和各种Shell程序一般而言是使用解释器执行的。微软公司的Qbasic语言也是解释方式,它不能生成可执行程序(但Quick Basic和Visual Basic可以);运用广泛的网络编程语言java则同时有解释和编译方式。
这里又将解释器分为了两种,一种是源代码解释器
、一种是伪代码解释器
当你写好一个Java程序后
,源语言的语句将由Java编译器编译成字节码
,而不是编译成与某个特定的处理器硬件平台对应的指令代码(比如,Intel的Pentium微处理器或IBM的System/390处理器)。字节码是可以发送给任何平台并且能在那个平台上运行的独立于平台的代码。(Eclipse、Ider)
JIT编译器,英文写作Just-In-Time Compiler,中文意思是即时编译器。
在Java编程语言和环境中,即时编译器
(JIT compiler,just-in-time compiler)是一个把Java的字节码``转换成可以直接发送给处理器的指令的程序
。
JIT是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态解释。静态编译的程序在执行前全部被翻译为机器码,而动态解释执行的则是一句一句边运行边翻译。
其实读完解释器后会发现解释器和JIT编译器还是没搞明白,别慌,看下面!
第一阶段,只使用了解释器:最早的Java建置方案是由一套转译程式(interpreter),
将每个Java指令都转译成对等的微处理器指令,并根据转译后的指令先后次序依序执行
,由于一个Java指令可能被转译成十几或数十几个对等的微处理器指令,这种模式执行的速度相当缓慢。(这个阶段就是Java刚诞生阶段,使用单纯的解释器完成的)
第二阶段,编译器出现了:针对这个问题,业界首先开发出JIT(just in time)编译器。当Java执行runtime环境时,每遇到一个新的类别(class:类别是Java程式中的功能群组),类别是Java程式中的功能群组-JIT编译器在此时就会针对这个类别进行编译(compile)作业。
经过编译后的程式,被优化成相当精简的原生型指令码(native code)
,这种程式的执行速度相当快。花费少许的编译时间来节省稍后相当长的执行时间
,JIT这种设计的确增加不少效率,但是它并未达到最顶尖的效能,因为某些极少执行到的Java指令在编译时所额外花费的时间可能比解释器在执行时的时间还长
,针对这些指令而言,整体花费的时间并没有减少
。
通俗的理解:明确目的是为了节约时间,所以不用解释器 了,我直接改用编译器。
为什么不用解释器了?
因为解释器他是由一个Java指令可能被转译成十几或数十几个对等的微处理器指令,然后一边转换指令一边执行着。
用编译器,虽然编译花点时间,但是我可以通过编译器将代码精简成原生型指令码(native code),然后在执行。这个相当于把时间花在了编译身上。
可能一些简单的代码, 通过解释器会更快点,因为解释器,他属于解析一点,执行一点。假如是这种情况,那单纯的使用编译器并达不到节约时间的目的。于是第三阶段来了。
第三阶段,解释器和编译器结合使用:基于对JIT的经验,业界发展出
动态编译器
(dynamic compiler),动态编译器仅针对较常被执行的程式码进行编译,其余部分仍使用转译程式来执行
。也就是说,动态编译器会研判是否要编译每个类别。动态编译器拥有两项利器:一是解释器,另一则是JIT
,它透过智慧机制针对每个类别进行分析
,然后决定使用这两种利器的哪一种来达到最佳化的效果。
动态编译器针对程式的特性或者是让程式执行几个循环,再根据结果决定是否编译这段程式码。这个决定不见得绝对正确,但从统计数字来看,这个判断的机制正确的机会相当高。事实上,动态编译器会根据「历史资料」做决策,所以程式执行的时间愈长,判断正确的机率就愈高。以整个结果来看,动态编译器产生的程式码执行的速度超越以前的JIT技术,平均速度可提高至50%。
在Java经历了这20年漫长的进化,除目前用的HotSpot虚拟机外,中间还出现了各种各样的虚拟机。在此列出了以下虚拟机种类。其实学习这些东西就跟考古一样,有的人读起来感觉枯燥乏味,而对于喜欢钻研和考古的人来说是一种享受。不仅仅是享受,还能从中了解到更有价值的学问。
正所谓学习不仅仅是学习,我们追求的是:知其然,更要知其所以然。
以今天的视角来看,Sun Classic虚拟机的技术已经相当原始,这款虚拟机的使命也早已终结。但 仅凭它“世界上第一款商用Java虚拟机”的头衔,就足够有令历史记住它的理由。
1996年1月23日,Sun发布JDK 1.0,Java语言首次拥有了商用的正式运行环境,这个JDK中所带的 虚拟机就是Classic VM
。这款虚拟机只能使用纯解释器方式来执行Java代码
,如果要使用即时编译器那 就必须进行外挂。
其中的“sunwjit”(Sun Workshop JIT)就是Sun提供的外挂编译器,其他类似的外挂编译器还有 Symantec JIT和shuJIT等。要使用编译执行,编译 器就不得不对每一个方法、每一行代码都进行编译,而无论它们执行的频率是否具有编译的价值。基 于程序响应时间的压力
,这些编译器根本不敢应用编译耗时稍高的优化技术
,因此这个阶段的虚拟机 虽然用了即时编译器输出本地代码,其执行效率也和传统的C/C++程序有很大差距,“Java语言很慢”的 印象就是在这阶段开始在用户心中树立起来的。
Sun的虚拟机团队努力去解决Classic虚拟机所面临的各种问题,提升运行效率,在JDK 1.2
时,曾 在Solaris平台上发布过一款名为Exact VM
的虚拟机,它的编译执行系统已经具备现代高性能虚拟机雏 形,如热点探测
、编译器与解释器混合工作模式
等。
Exact VM因它使用准确式内存管理
(Exact Memory Management,也可以叫Non-Con- servative/Accurate Memory Management)而得名。准确式内存管理是指虚拟机可以知道内存中某个位 置的数据具体是什么类型
。譬如内存中有一个32bit的整数123456,虚拟机将有能力分辨出它到底是一 个指向了123456的内存地址的引用类型还是一个数值为123456的整数,准确分辨出哪些内存是引用类 型
,这也是在垃圾收集时准确判断堆上的数据是否还可能被使用的前提
。由于使用了准确式内存管 理,Exact VM可以抛弃掉以前Classic VM基于句柄(Handle)的对象查找方式
,这样每次定位对象都少了一次间接查找的开销,显著提升执行性能
。
虽然Exact VM
的技术相对Classic VM来说先进了许多,但是它的命运显得十分英雄气短,在商业 应用上只存在了很短暂的时间就被外部引进的HotSpot VM所取代
,甚至还没有来得及发布Windows和 Linux平台下的商用版本。而Classic VM的生命周期则相对要长不少,它在JDK 1.2之前是JDK中唯一的 虚拟机
,在JDK 1.2时
,它与HotSpot VM并存,但默认是使用Classic VM
(用户可用java-hotspot参数 切换至HotSpot VM
),而在JDK 1.3时,HotSpot VM成为默认虚拟机
,它仍作为虚拟机的“备用选 择”发布(使用java-classic参数切换),直到JDK 1.4的时候
,Classic VM
才完全退出
商用虚拟机的历史 舞台,与Exact VM一起进入了Sun Labs Research VM
之中。
相信所有Java程序员都听说过HotSpot虚拟机
,它是Sun/OracleJDK和OpenJDK中的默认Java虚拟 机
,也是目前使用范围最广的Java虚拟机。但不一定所有人都知道的是,这个在今天看起来“血统纯 正”的虚拟机在最初并非由Sun公司所开发,而是由一家名为“Longview Technologies”的小公司设计
;甚 至这个虚拟机最初并非是为Java语言而研发的,它来源于Strongtalk虚拟机,而这款虚拟机中相当多的 技术又是来源于一款为支持Self语言实现
“达到C语言50%以上的执行效率
”的目标而设计的Self虚拟机, 最终甚至可以追溯到20世纪80年代中期开发的Berkeley Smalltalk上。Sun公司
注意到这款虚拟机在即时 编译等多个方面有着优秀的理念和实际成果,在1997年收购了Longview Technologies公司,从而获得了 HotSpot虚拟机
。
HotSpot既继承了Sun之前两款商用虚拟机的优点
(如前面提到的准确式内存管理),也有许多自 己新的技术优势,如它名称中的HotSpot指的就是它的热点代码探测技术
,HotSpot虚拟机的热点代码探测能力可以通过执行计数器
找出最具有编译价值的代码
,然后通知即时编译器以方法为单位进行编译
。如果一个方法被频繁调 用,或方法中有效循环次数很多,将会分别触发标准即时编译和栈上替换编译
(On-Stack Replacement,OSR)行为。通过编译器与解释器恰当地协同工作
,可以在最优化的程序响应时间与 最佳执行性能中取得平衡
,而且无须等待本地代码输出才能执行程序
,即时编译的时间压力也相对减 小,这样有助于引入更复杂的代码优化技术,输出质量更高的本地代码。
通俗的理解:HotSpot VM由解释器、即时编译器、和热点代码检测,来完成了整套优化流程。
当程序刚运行起来是解释器和热点代码检测一直在工作,然后热点代码检测到经常被调用的方法了,于是会告诉即时编译器,让他进行编译,通过对这个方法的编译,他就变成了原生型指令码(native),当再次被调用的时候,直接执行原指令。
2006年,HotSpot从此成为Sun/OracleJDK和OpenJDK两个实现极度接近的JDK项目 的共同虚拟机。Oracle收购Sun
以后,建立了HotRockit项目来把原来BEA JRockit中的优秀特性融合到 HotSpot之中
。到了2014年的JDK 8时期
,里面的HotSpot就已是两者融合的结果
,HotSpot在这个过程 里移除掉永久代
,吸收了JRockit的Java Mission Control监控工具等功能
。
得益于Sun/OracleJDK在Java应用中的统治地位,HotSpot理所当然地成为全世界使用最广泛的Java 虚拟机,是虚拟机家族中毫无争议的“武林盟主”。
Sun/Oracle公司所研发的虚拟机可不仅包含前面介绍到的服务器、桌面领域的商用虚拟机,面对移动和嵌入式
市场,也有专门的Java虚拟机
产品。
由于Java ME产品线的发展相对Java SE来说并不那么成功,所以Java ME中的Java虚拟机相比 HotSpot要低调得多。Oracle公司在Java ME
这条产品线上的虚拟机名为CDC-HI
(C Virtual Machine, CVM)和CLDC-HI
(Monty VM)。其中CDC/CLDC全称是Connected
(Limited)Device Configuration,这是一组在JSR-139及JSR-218规范中进行定义的Java API子集,这组规范希望能够在手 机、电子书、PDA等移动设备上建立统一的Java编程接口,CDC-HI VM和CLDC-HI VM就是JSR-139 及JSR-218规范的参考实现,后面的HI则是HotSpot Implementation的缩写,但它们并不是由HotSpot直 接裁剪而来,只是借鉴过其中一些技术,并没有血缘关系,充其量能叫有所渊源。
Java ME中的Java虚拟机现在处于比较尴尬的位置,所面临的局面远不如服务器和桌面领域乐观, 它最大的一块市场——智能手机已被Android和iOS二分天下,现在CDC在智能手机上略微有点声音 的产品是Oracle ADF Mobile
,原本它提出的卖点是智能手机上的跨平台(“Developing with Java on iOS and Android”),不过用Java在Android上开发应用还要再安装个CDC虚拟机,这事情听着就觉得别 扭
,有多此一举的嫌疑,在iOS上倒确实还有一些人在用
。
而在嵌入式设备上,Java ME
Embedded又面临着自家Java SE Embedded(eJDK)的直接竞争和侵 蚀,主打高端的CDC-HI经过多年来的扩充,在核心部分其实已经跟Java SE非常接近
,能用Java SE的 地方大家自然就不愿意用Java ME
,所以市场在快速萎缩,Oracle
也基本上砍掉了CDC-HI的所有项 目
,把它们都划归到了Java SE Embedded下
。Java SE Embedded
里带的Java虚拟机当然还是HotSpot
,但 这是为了适应嵌入式环境专门定制裁剪的版本,尽可能在支持完整的Java SE功能的前提下向着减少内 存消耗的方向优化
,譬如只留下了客户端编译器(C1),去掉了服务端编译器(C2);只保留 Serial/Serial Old垃圾收集器,去掉了其他收集器等。
面向更低端设备的CLDC-HI倒是在智能控制器、传感器等领域还算能维持自己的一片市场,现在 也还在继续发展,但前途并不乐观。目前CLDC中活得最好的产品反而是原本早该被CLDC-HI淘汰的 KVM
,国内的老人手机和出口到经济欠发达国家的功能手机(Feature Phone)还在广泛使用这种更加 简单、资源消耗也更小的上一代Java ME
虚拟机。
在中国,传音手机的出货量超 过小米、OPPO、VIVO等智能手机巨头,仅次于华为(含荣耀品牌)排行全国第二。传音手机做的是 功能机,销售市场主要在非洲,上面仍然用着Java ME的KVM。
前面三节介绍的都是由Sun/Oracle公司研发的Java虚拟机,历史上除了Sun/Oracle公司以外,也有其 他组织、公司开发过虚拟机的实现。如果说HotSpot是天下第一的武林盟主,那曾经与HotSpot并称“三 大商业Java虚拟机”
的另外两位,毫无疑问就该是天下第二了,它们分别是BEA System公司
的JRockit
与 IBM公司的IBM J9
。
JRockit
虚拟机曾经号称
是“世界上速度最快的Java虚拟机
”(广告词,IBM J9虚拟机也这样宣传 过,总体上三大虚拟机的性能是交替上升的),它是BEA在2002年从Appeal Virtual Machines公司收购 获得的Java虚拟机。BEA将其发展为一款专门为服务器硬件
和服务端应用场景高度优化的虚拟机
,由 于专注于服务端应用
,它可以不太关注于程序启动速度
,因此JRockit内部不包含解释器实现
,全部代 码都靠即时编译器编译后执行
。除此之外,JRockit的垃圾收集器和Java Mission Control故障处理套件 等部分的实现,在当时众多的Java虚拟机中也处于领先水平。JRockit随着BEA被Oracle收购,现已不再 继续发展
,永远停留在R28版本,这是JDK 6版JRockit的代号。
IBM J9虚拟机并不是IBM公司唯一的Java虚拟机,不过目前IBM主力发展无疑就是J9。J9这个名 字最初只是内部开发代号而已,开始选定的正式名称是“IBM Technology for Java Virtual Machine”,简 称IT4J,但这个名字太拗口,接受程度远不如J9。J9虚拟机最初是由IBM Ottawa实验室的一个 SmallTalk虚拟机项目扩展而来
,当时这个虚拟机有一个Bug是因为8KB常量值定义错误引起
,工程师们 花了很长时间终于发现并解决了这个错误,此后这个版本的虚拟机就被称为K8
,后来由其扩展而来、 支持Java语言的虚拟机就被命名为J9
。与BEA JRockit只专注于服务端应用不同,IBM J9虚拟机的市场 定位与HotSpot比较接近
,它是一款在设计上全面考虑服务端、桌面应用,再到嵌入式的多用途虚 拟机,开发J9的目的是作为IBM公司各种Java产品的执行平台
,在和IBM产品(如IBM WebSphere等) 搭配以及在IBM AIX和z/OS这些平台上部署Java应用。
IBM J9直至今天仍旧非常活跃,IBM J9虚拟机的职责分离与模块化
做得比HotSpot更优秀
,由J9 虚拟机
中抽象封装出来的核心组件库
(包括垃圾收集器、即时编译器、诊断监控子系统等)就单独构 成了IBM OMR项目
,可以在其他语言平台如Ruby、Python中快速组装成相应的功能。从2016年起
, IBM逐步将OMR项目和J9虚拟机进行开源,完全开源后便将它们捐献给了Eclipse基金会管理
,并重新 命名为Eclipse OMR和OpenJ9
。如果为了学习虚拟机技术而去阅读源码,更加模块化的OpenJ9代码 其实是比HotSpot更好的选择。如果为了使用Java虚拟机时多一种选择,那可以通过AdoptOpenJDK来 获得采用OpenJ9搭配上OpenJDK其他类库组成的完整JDK。
除BEA和IBM公司外,其他一些大公司也号称有自己的专属JDK和虚拟机,但是它们要么是通过 从Sun/Oracle公司购买版权的方式获得的(如HP、SAP等),要么是基于OpenJDK项目改进而来的 (如阿里巴巴、Twitter等),都并非自己独立开发。
严格来说,J9能够支持的市场定位比HotSpot更加广泛
,J9最初是为嵌入式领域设计的,后来逐渐 扩展为IBM所有平台共用的虚拟机,嵌入式、桌面、服务器端都用它,而HotSpot在嵌入式领域使用的 是CDC/CLDC以及Java SE Embedded
,这也从侧面体现了J9的模块化和通用性做得非常好
。尽管OpenJ9名称上看起来与OpenJDK类似,但它只是一个单独的Java虚拟机
,不包括JDK中的其他 内容
,实际应该与HotSpot相对应。
我们平时所提及的“高性能Java虚拟机”一般是指HotSpot、JRockit、J9这类在通用硬件平台上运行 的商用虚拟机,但其实还有一类与特定硬件平台绑定、软硬件配合工作的专有虚拟机
,往往能够实现 更高的执行性能,或提供某些特殊的功能特性。这类专有虚拟机的代表是BEA Liquid VM和Azul VM
。
Liquid VM
也被称为JRockit VE(Virtual Edition,VE),它是BEA公司开发
的可以直接运行在自家 Hypervisor系统上的JRockit虚拟机的虚拟化版本,Liquid VM不需要操作系统的支持,或者说它自己本 身实现了一个专用操作系统的必要功能
,如线程调度、文件系统、网络支持
等。由虚拟机越过通用操 作系统直接控制硬件
可以获得很多好处,如在线程调度时,不需要再进行内核态/用户态的切换,这样 可以最大限度地发挥硬件的能力,提升Java程序的执行性能
。随着JRockit虚拟机终止开发,Liquid VM 项目也已经停止了。
Azul VM是Azul Systems公司在HotSpot基础上进行大量改进
,运行于
Azul Systems公司的专有硬 件Vega
系统上的Java虚拟机,每个Azul VM实例都可以管理至少数十个CPU和数百GB的内存的硬件资 源,并提供在巨大内存范围内停顿时间可控的垃圾收集器
(即业内赫赫有名的PGC和C4收集器),为 专有硬件优化的线程调度等优秀特性。2010年
起,Azul公司
的重心逐渐开始从硬件转向软件,发布了
自己的Zing虚拟机
,可以在通用x86平台上提供接近于Vega系统的性能和一致的功能特性。
随着虚拟机技术的不断发展,Java虚拟机变得越来越强大的同时也越来越复杂,要推动在专有硬 件上的Java虚拟机升级发展,难以直接借助开源社区的力量
,往往需要耗费更高昂的成本,在商业上 的缺陷使得专有虚拟机逐渐没落,Azul Systems公司最终也放弃了Vega产品线
,把全部精力投入到Zing 和Zulu产品线中。
Zing虚拟机是一个从HotSpot某旧版代码分支基础上独立出来重新开发的高性能Java虚拟机
,它可 以运行在通用的Linux/x86-64平台上。Azul公司为它编写了新的垃圾收集器,也修改了HotSpot内的许 多实现细节,在要求低延迟、快速预热等场景中,Zing VM都要比HotSpot表现得更好。Zing的PGC、 C4收集器可以轻易支持TB级别的Java堆内存
,而且保证暂停时间仍然可以维持在不超过10毫秒的范围 里,HotSpot要一直到JDK 11和JDK 12的ZGC及Shenandoah收集器才达到了相同的目标
,而且目前效 果仍然远不如C4。Zing的ReadyNow!功能可以利用之前运行时收集到的性能监控数据
,引导虚拟机 在启动后快速达到稳定的高性能水平,减少启动后从解释执行到即时编译的等待时间
。Zing自带的 ZVision/ZVRobot功能可以方便用户监控Java虚拟机的运行状态
,从找出代码热点到对象分配监控、锁 竞争监控等。Zing能让普通用户无须了解垃圾收集等底层调优
,就可以使得Java应用享有低延迟、快 速预热、易于监控的功能,这是Zing的核心价值和卖点
,很多Java应用都可以通过长期努力在应用、 框架层面优化来提升性能,但使用Zing的话就可以把精力更多集中在业务方面
。
这节介绍的Harmony
虚拟机(准确地说是Harmony里的DRLVM)和Dalvik
虚拟机只能称作“虚拟 机”
,而不能称作“Java虚拟机”
,但是这两款虚拟机以及背后所代表的技术体系曾经对Java世界产生了 非常大的影响和挑战,当时甚至有悲观的人认为成熟的Java生态系统都有分裂和崩溃的可能。
Apache Harmony是一个Apache软件基金会旗下以Apache License协议
开源的实际兼容于JDK 5和 JDK 6的Java程序运行平台
,它含有自己的虚拟机和Java类库API,用户可以在上面运行Eclipse、 Tomcat、Maven等常用的Java程序
。但是,它并没有通过TCK认证
,所以我们不得不用一长串冗长拗 口的语言来介绍它,而不能用一句“Apache的JDK”或者“Apache的Java虚拟机”来直接代指。
如果一个公司要宣称自己的运行平台“兼容于Java技术体系”,那该运行平台就必须要通过 TCK(Technology Compatibility Kit)的兼容性测试,Apache基金会曾要求当时的Sun公司提供TCK的 使用授权,但是一直遭到各种理由的拖延和搪塞,直到Oracle收购了Sun公司之后,双方关系越闹越 僵,最终导致Apache基金会愤然退出JCP组织
,这是Java社区有史以来最严重的分裂事件之一。
当Sun公司
把自家的JDK开源形成OpenJDK
项目之后,Apache Harmony开源的优势被极大地抵 消,以至于连Harmony项目的最大参与者IBM公司
也宣布辞去Harmony项目管理主席的职位,转而参 与OpenJDK的开发
。虽然Harmony没有真正地被大规模商业运用过
,但是它的许多代码(主要是Java 类库部分的代码)被吸纳进IBM的JDK 7实现以及Google Android SDK之中,尤其是对Android的发展 起了很大推动作用
。
说到Android,这个时下最热门的移动数码设备平台在最近十年所取得的成果已经远远超越了Java ME在过去二十多年所获得的成果,Android让Java语言真正走进了移动数码设备领域,只是走得并非 Sun公司原本想象的那一条路。
Dalvik虚拟机曾经是Android平台的核心组成部分之一
,它的名字来源于冰岛一个名为Dalvik的小 渔村。Dalvik虚拟机并不是一个Java虚拟机
,它没有遵循《Java虚拟机规范》,不能直接执行Java的 Class文件
,使用寄存器架构而不是Java虚拟机中常见的栈架构。但是它与Java却又有着千丝万缕的联 系,它执行的DEX
(Dalvik Executable)文件可以通过Class文件转化而来
,使用Java语法编写应用程 序,可以直接使用绝大部分的Java API等
。在Android发展的早期,Dalvik虚拟机随着Android的成功迅 速流行,在Android 2.2中开始提供即时编译器实现,执行性能又有了进一步提高。不过到了Android 4.4时代,支持提前编译
(Ahead of Time Compilation,AOT)的ART虚拟机迅速崛起
,在当时性能还 不算特别强大的移动设备上,提前编译要比即时编译更容易获得高性能
,所以在Android 5.0里ART就 全面代替了Dalvik虚拟机
。
在Java虚拟机二十几年的发展历程中,除去上面介绍的那些被大规模商业应用过的Java虚拟机外, 还有许多虚拟机是不为人知地默默沉寂,或者曾经绚丽过但最终夭折湮灭的。我们以其中Microsoft公 司的Java虚拟机
为代表来介绍一下。
在Java语言诞生的初期(1996年~1998年,以JDK1.2发布之前为分界),它的主要应用之一是在 浏览器中运行Java Applets程序
,微软为了在Internet Explorer 3浏览器中支持Java Applets应用而开发了 自己的Java虚拟机,虽然这款虚拟机只有Windows平台的版本,“一次编译,到处运行”根本无从谈起, 但却是当时Windows系统下性能最好的Java虚拟机
,它在1997年和1998年连续获得了《PC Magazine》 杂志的“编辑选择奖”。但是好景不长,在1997年10月,Sun公司正式以侵犯商标、不正当竞争等罪名控 告微软
,在随后对微软公司的垄断调查之中,这款虚拟机也曾作为证据之一被呈送法庭。官司的结果 是微软向Sun公司
(最终微软因垄断赔偿给Sun公司的总金额高达10亿美元)赔偿2000万美金
,承诺终 止其Java虚拟机的发展
,并逐步在产品中移除Java虚拟机相关功能。而最令人感到讽刺的是,到后来在 Windows XP SP3中Java虚拟机被完全抹去的时候,Sun公司却又到处登报希望微软不要这样做。
Windows XP高级产品经理Jim Cullinan称:“我们花费了三年的时间和Sun公司打官司,当时他们试图阻 止我们在Windows中支持Java,现在我们这样做了,可他们又在抱怨,这太具有讽刺意味了。”
我们试想一下,如果当年Sun公司没有起诉微软公司,微软继续保持着对Java技术的热情,那Java 的世界会变得更好还是更坏?.NET技术是否还会发展起来?
还有一些Java虚拟机天生就注定不会应用在主流领域,或者不是单纯为了用于生产,甚至在设计 之初就没有抱着商用的目的,仅仅是用于研究、验证某种技术和观点,又或者是作为一些规范的标准 实现。这些虚拟机对于大多数不从事相关领域开发的Java程序员来说可能比较陌生,笔者列举几款较 为有影响的:
KVM
KVM
中的K是“Kilobyte”的意思,它强调简单、轻量、高度可移植,但是运行速度比较慢
。在 Android、iOS等智能手机操作系统出现前曾经在手机平台上得到非常广泛应用。
Java Card VM
JCVM是Java虚拟机很小的一个子集
,裁减了许多模块但通常支持绝大多数的常用加密算法。 JCVM必须精简到能放入智能卡、SIM卡、银行信用卡、借记卡内
,负责对Java Applet程序进行解释执 行
。
Squawk VM
Squawk VM
是由Sun开发,运行于Sun SPOT
(Sun Small Programmable Object Tech-nology,一种手 持的Wi-Fi设备
),也曾经运用于Java Card。这是一个Java代码比重很高的嵌入式虚拟机实现
,其中诸 如类加载器、字节码验证器、垃圾收集器、解释器、编译器和线程调度都是用Java语言完成的,仅仅 靠C语言来编写设备I/O和必要的本地代码。
JavaInJava
JavaInJava
是Sun公司在1997年~1998年间所研发的一个实验室性质的虚拟机,从名字就可以看 出,它试图以Java语言来实现Java语言本身的运行环境
,既所谓的“元循环”(Meta-Circular,是指使用 语言自身来实现其运行环境)虚拟机。它必须运行在另外一个宿主虚拟机之上,内部没有即时编译 器,代码只能以解释模式执行。在上世纪末主流原生的Java虚拟机都未能很好解决性能问题的时代, 开发这种项目,其执行速度大家可想而知,不过通过元循环证明一门语言可以自举,是具有它的研究 价值的。
Maxine VM
Maxine VM
和上面的JavaInJava非常相似,它也是一个几乎全部以Java代码实现
(只有用于启动 Java虚拟机的加载器使用C语言编写)的元循环Java虚拟机
。这个项目于2005年开始,到现在仍然在发 展之中,比起JavaInJava,Maxine VM的执行效率就显得靠谱得多,它有先进的即时编译器和垃圾收集 器,可在宿主模式或独立模式下执行,其执行效率已经接近HotSpot虚拟机Client模式的水平。后来有 了从C1X编译器演进而来的Graal编译器的支持,就更加如虎添翼,执行效率有了进一步飞跃。Graal编 译器现在已经是HotSpot的默认组件,是未来代替HotSpot中服务端编译器的希望
。
Jikes RVM
Jikes RVM
是IBM开发的专门用来研究Java虚拟机实现技术的项目。曾用名为Jalapeño。与 JavaInJava和Maxine一样,它也是一个元循环虚拟机
。
IKVM.NET
这是一个基于微软.NET框架实现的Java虚拟机
,并借助Mono获得一定的跨平台能力。IKVM.NET 的目标第一眼看起来的确很奇怪,可能在某些特殊情况下,在.NET上使用某些流行的Java库也许真的 不算是伪需求?IKVM.NET可以将Class文件编译成.NET Assembly,在任意的CLI上运行
。
这里把Java ME里面的虚拟机列为“少数派”是从大多数Java程序员的了解程度出发的,从虚拟机部 署数量来讲,Java ME远比Java SE、Java EE的虚拟机多,毕竟服务器应用是无法在数量上和移动、嵌 入式设备比较的。
文章部分源于 【深入理解Java虚拟机】 一书当中,部分源于 【百度百科】当中。