Java虚拟机进阶之一:Java VM前世此生html
目标:java
1, Java技术体系,从两种分类来看。编程
2, 解释器和编译器的概念及配合工做原理。小程序
3, 各类Java虚拟机的介绍。安全
4, JVM的趋势:多语言混合编程。服务器
5, 64位虚拟机的优缺点及替代方案。架构
6, 如何获取JDK源码并发
7,Java和Java虚拟机的关系框架
前言编程语言
Java开发技术自己的一个重要优势致使:在虚拟机层面隐藏了底层技术的复杂性以及机器与操做系统的差别性。
Java虚拟机的缘由:为了达到给全部硬件提供一致的虚拟平台的目的,牺牲了一些与硬件相关的性能特性。
第1章 走近Java
世界上并无完美的程序,但咱们并不所以而沮丧,由于写程序原本就是一个不断追求完美的过程。
1.2 Java技术体系
从广义上讲,Clojure、JRuby、Groovy等运行于Java虚拟机上的语言及其相关的程序都属于Java技术体系中的一员。
仅从传统意义上来看,Sun官方所定义的Java技术体系包括如下几个组成部分:
1, Java程序设计语言
2,各类硬件平台上的Java虚拟机
3, Class文件格式
4,Java API类库
5,来自商业机构和开源社区的第三方Java类库
若是按照技术所服务的领域来划分,或者说按照Java技术关注的重点业务领域来划分,Java技术体系能够分为4个平台,分别为: 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外,还对其作了大量的扩充并提供了相关的部署支持,这个版本之前称为J2EE。
1, Java Card
2, Java Me
3, Java SE
4, Java EE
1.3 Java发展史
这个版本中Java虚拟机第一次内置了JIT(Just In Time)编译器(JDK 1.2中曾并存过3个虚拟机,Classic VM、HotSpot VM和Exact VM,其中Exact VM只在Solaris平台出现过;后面两个虚拟机都是内置JIT编译器的,而以前版本所带的Classic VM只能之外挂的形式使用JIT编译器)
Q:什么是解释器,什么是编译器?
解释器就是虚拟机将源代码编译成一种中间的字节码(class文件),与机器平台无关
编译器就是虚拟机将源代码编译成和本地机器平台相关的机器语言。
Q:什么是JIT编译器?
即时编译器(Just In Time Compiler) 简称JIT。
JAVA程序最初是经过解释器(Interpreter)进行解释执行的,当JVM发现某个方法或代码块运行特别频繁的时候,就会认为这是“热点代码”(Hot Spot Code)。
为了提升热点代码的执行效率,就会将这些“热点代码”编译成与本地机器相关的机器码,进行各个层次的优化。 完成这个任务的编译器就是即时编译器(JIT)。
Q:解释器和编译器之间是如何配合的?
一、当程序须要迅速启动和执行的时候,解析器首先发挥做用,省去编译的时间,当即执行。随着时间的推移,编译器发挥做用,把愈来愈多的代码编译成本地代码,得到更高的执行效率。
二、当机器内存限制比较大,能够用解析方式节约内存,反之能够用编译提高效率。
三、解析器还能够做为编译器的“逃生门”。当例如加载了新类后类型结构发生变化,能够采用逆优化,退回到解析状态继续执行。
Oracle公司分别从BEA和Sun中取得了目前三大商业虚拟机的其中两个:JRockit和HotSpot,
1.4.1 Sun Classic/Exact VM
1996年1月23日,Sun公司发布JDK 1.0,Java语言首次拥有了商用的正式运行环境,这个JDK中所带的虚拟机就是Classic VM。这款虚拟机只能使用纯解释器方式来执行Java代码,若是要使用JIT编译器,就必须进行外挂。可是假如外挂了JIT编译器,JIT编译器就彻底接管了虚拟机的执行系统,解释器便再也不工做了。
因为解释器和编译器不能配合工做,这就意味着若是要使用编译器执行,编译器就不得不对每个方法、每一行代码都进行编译,而不管它们执行的频率是否具备编译的价值。基于程序响应时间的压力,这些编译器根本不敢应用编译耗时稍高的优化技术,所以这个阶段的虚拟机即便用了JIT编译器输出本地代码,执行效率也和传统的C/C++程序有很大差距,“Java语言很慢”的形象就是在这时候开始。
Exact VM的虚拟机,它的执行系统已经具有现代高性能虚拟机的雏形:如两级即时编译器、编译器与解释器混合工做模式等。Exact VM因它使用准确式内存管理(Exact Memory Management,也能够叫Non-Conservative/Accurate Memory Management)而得名,即虚拟机能够知道内存中某个位置的数据具体是什么类型。譬如内存中有一个32位的整数123456,它究竟是一个reference类型指向123456的内存地址仍是一个数值为123456的整数,虚拟机将有能力分辨出来,这样才能在GC(垃圾收集)的时候准确判断堆上的数据是否还可能被使用。因为使用了准确式内存管理,Exact VM能够抛弃之前Classic VM基于handler的对象查找方式(缘由是进行GC后对象将可能会被移动位置,若是将地址为123456的对象移动到654321,在没有明确信息代表内存中哪些数据是reference的前提下,虚拟机是不敢把内存中全部为123456的值改为654321的,因此要使用句柄来保持reference值的稳定),这样每次定位对象都少了一次间接查找的开销,提高执行性能。
1.4.2 Sun HotSpot VM
HotSpot VM的热点代码探测能力能够经过执行计数器找出最具备编译价值的代码,而后通知JIT编译器以方法为单位进行编译。若是一个方法被频繁调用,或方法中有效循环次数不少,将会分别触发标准编译和OSR(栈上替换)编译动做。经过编译器与解释器恰当地协同工做,能够在最优化的程序响应时间与最佳执行性能中取得平衡,并且无须等待本地代码输出才能执行程序,即时编译的时间压力也相对减少,这样有助于引入更多的代码优化技术,输出质量更高的本地代码。
在2008年和2009年,Oracle公司分别收购了BEA公司和Sun公司,这样Oracle就同时拥有了两款优秀的Java虚拟机:JRockit VM和HotSpot VM。Oracle公司宣布在不久的未来(大约应在发布JDK 8的时候)会完成这两款虚拟机的整合工做,使之优点互补。整合的方式大体上是在HotSpot的基础上,移植JRockit的优秀特性,譬如使用JRockit的垃圾回收器与MissionControl服务,使用HotSpot的JIT编译器与混合的运行时系统。
1.4.4 BEA JRockit/IBM J9 VM
JRockit VM曾经号称“世界上速度最快的Java虚拟机”(广告词,貌似J9 VM也这样说过),它是BEA公司在2002年从Appeal Virtual Machines公司收购的虚拟机。BEA公司将其发展为一款专门为服务器硬件和服务器端应用场景高度优化的虚拟机,因为专一于服务器端应用,它能够不太关注程序启动速度,所以JRockit内部不包含解析器实现,所有代码都靠即时编译器编译后执行。除此以外,JRockit的垃圾收集器和MissionControl服务套件等部分的实现,在众多Java虚拟机中也一直处于领先水平。
1.4.5 Azul VM/BEA Liquid VM
咱们平时所说起的“高性能Java虚拟机”通常是指HotSpot、JRockit、J9这类在通用平台上运行的商用虚拟机,但其实Azul VM和BEA Liquid VM这类特定硬件平台专有的虚拟机才是“高性能”的武器。
1.4.6 Apache Harmony/Google Android Dalvik VM
Dalvik VM并非一个Java虚拟机,它没有遵循Java虚拟机规范,不能直接执行Java的Class文件,使用的是寄存器架构而不是JVM中常见的栈架构。可是它与Java又有着千丝万缕的联系,它执行的dex(Dalvik Executable)文件能够经过Class文件转化而来,使用Java语法编写应用程序,能够直接使用大部分的Java API等。目前Dalvik VM随着Android一块儿处于迅猛发展阶段,在Android 2.2中已提供即时编译器实现,在执行性能上有了很大的提升。
1.5.2 混合语言
Java平台上的多语言混合编程正成为主流,每种语言均可以针对本身擅长的方面更好地解决问题。
想一下,在一个项目之中,并行处理用Clojure语言编写,展现层使用JRuby/Rails,中间层则是Java,每一个应用层都将使用不一样的编程语言来完成,并且,接口对每一层的开发者都是透明的,各类语言之间的交互不存在任何困难,就像使用本身语言的原生API同样方便,由于它们最终都运行在一个虚拟机之上
在最近的几年里,Clojure、JRuby、Groovy等新生语言的使用人数不断增加,而运行在Java虚拟机(JVM)之上的语言数量也在迅速膨胀,图1-4中列举了其中的一部分。这两点证实混合编程在咱们身边已经有所应用并被普遍承认。经过特定领域的语言去解决特定领域的问题是当前软件开发应对日趋复杂的项目需求的一个方向。
对这些运行于Java虚拟机之上、Java以外的语言,来自系统级的、底层的支持正在迅速加强,以JSR-292为核心的一系列项目和功能改进(如Da Vinci Machine项目、Nashorn引擎、InvokeDynamic指令、java.lang.invoke包等),推进Java虚拟机从“Java语言的虚拟机”向“多语言虚拟机”的方向发展。
1.5.3 多核并行
早在JDK 1.5就已经引入java.util.concurrent包实现了一个粗粒度的并发框架。而JDK 1.7中加入的java.util.concurrent.forkjoin包则是对这个框架的一次重要扩充。Fork/Join模式是处理并行编程的一个经典方法,
在Java 8中,将会提供Lambda支持,这将会极大改善目前Java语言不适合函数式编程的现状(目前Java语言使用函数式编程并非不能够,只是会显得很臃肿),函数式编程的一个重要优势就是这样的程序自然地适合并行运行,这对Java语言在多核时代继续保持主流语言的地位有很大帮助。
1.5.5 64位虚拟机
Java虚拟机也在很早以前就推出了支持64位系统的版本。但Java程序运行在64位虚拟机上须要付出比较大的额外代价:
首先是内存问题,因为指针膨胀和各类数据类型对齐补白的缘由,运行于64位系统上的Java应用须要消耗更多的内存,一般要比32位系统额外增长10%~30%的内存消耗;
其次,多个机构的测试结果显示,64位虚拟机的运行速度在各个测试项中几乎全面落后于32位虚拟机,二者大约有15%左右的性能差距。
可是在Java EE方面,企业级应用常常须要使用超过4GB的内存,对于64位虚拟机的需求是很是迫切的,但因为上述缘由,许多企业应用都仍然选择使用虚拟集群等方式继续在32位虚拟机中进行部署。
1.6 实战:本身编译JDK
想要一探JDK内部的实现机制,最便捷的路径之一就是本身编译一套JDK,经过阅读和跟踪调试JDK源码去了解Java技术体系的原理,虽然门槛会高一点,但确定会比阅读各类书籍、文章更加贴近本质。另外,JDK中的不少底层方法都是本地化(Native)的,须要跟踪这些方法的运做或对JDK进行Hack的时候,都须要本身编译一套JDK。
1.6.1 获取JDK源码
获取OpenJDK源码有两种方式:
对于通常读者,建议采用第二种方式,即直接下载官方打包好的源码包,读者能够从Source Bundle Releases页面(地址:http://jdk7.java.net/source.html)取得打包好的源码,到本地直接解压便可。
For MoreDetails(官方文档):
参看官网文档java及java vm相关部分,提到一个问题:
Q: Java 和Java虚拟机的关系
Java 虚拟机并不局限于特定的实现技术、主机硬件和操做系统,Java 虚拟机也不局限于特定的代码执行方式,它不强求使用解释器来执行程序,也能够经过把本身的指令集编译为实际 CPU 的指令来实现,它能够经过微代码(Microcode)来实现,或者甚至直接实如今 CPU 中。
Java 虚拟机与 Java 语言并无必然的联系,它只与特定的二进制文件格式——Class 文件
格式所关联,Class 文件中包含了 Java 虚拟机指令集(或者称为字节码、Bytecodes)和符号表,还有一些其余辅助信息。
基于安全方面的考虑,Java 虚拟机要求在 Class 文件中使用了许多强制性的语法和结构化
约束,但任一门功能性语言均可以表示为一个能被 Java 虚拟机接收的有效的 Class 文件。做为一个通用的、机器无关的执行平台,任何其余语言的实现者均可以将 Java 虚拟机做为他们语言的产品交付媒介。