博主
258
258
258
258
专辑

第一节 JVM简介

亮子 2021-10-07 19:03:44 4988 0 0 0

JVM

1、什么是JVM

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

2、JVM的架构

Java虚拟机有自己完善的硬件架构,如处理器、堆栈等,还具有相应的指令系统。
Java虚拟机本质上就是一个程序,当它在命令行上启动的时候,就开始执行保存在某字节码文件中的指令。Java语言的可移植性正是建立在Java虚拟机的基础上。任何平台只要装有针对于该平台的Java虚拟机,字节码文件(.class)就可以在该平台上运行。这就是“一次编译,多次运行”。

Java虚拟机不仅是一种跨平台的软件,而且是一种新的网络计算平台。该平台包括许多相关的技术,如符合开放接口标准的各种API、优化技术等。Java技术使同一种应用可以运行在不同的平台上。Java平台可分为两部分,即Java虚拟机(Java virtual machine,JVM)和Java API类库。

每个Java程序都离不开Java虚拟机,Java程序的运行依靠具体的Java虚拟机实例。在Java虚拟机规范中,分别用子系统、内存区、数据类型以及指令这几个术语来描述的。这些组成部分一起展示出一个抽象化的虚拟机内部的抽象体系结构。

Java虚拟机主要分为五大模块:类装载器子系统、运行时数据区、执行引擎、本地方法接口和垃圾收集模块。

JVM

其中垃圾收集模块在Java虚拟机规范中并没有要求Java虚拟机垃圾收集,但是在没有发明无限的内存之前,大多数JVM实现都是有垃圾收集的。而运行时数据区都会以某种形式存在于每一个JAVA虚拟机实例中,但是Java虚拟机规范对它的描述却是相当抽象。这些运行时数据结构上的细节,大多数都由具体实现的设计者决定。

Java虚拟机不是真实的物理机,它没有寄存器,所以指令集是使用Java栈来存储中间数据,这样做的目的就是为了保持Java虚拟机的指令集尽量的紧凑,同时也便于JAVA虚拟机在那些只有很少通用寄存器的平台上实现。另外,JAVA虚拟机的这种基于栈的体系结构,有助于运行时某些虚拟机实现的动态编译器和即时编译器的代码优化。

3、JVM的位置

JVM的位置

4、JVM的种类

Java EE是以Java SE为基础的。所以并没有“JVM for Java EE”这么一说,只有“JVM for Java SE”,可以用于Java SE与Java EE。

在这个类别下,主流选择有:(按流行程度递减)

  • HotSpot VM
  • J9 VM
  • Zing VM

1)、HotSpot VM

(1)、流行度

HotSpot VM是绝对的主流。大家用它的时候很可能就没想过还有别的选择,或者是为了迁就依赖了Oracle/Sun JDK某些具体实现的烂代码而选择用HotSpot VM省点心。

Oracle / Sun JDK、OpenJDK的各种变种(例如IcedTea、Zulu),用的都是相同核心的HotSpot VM。

从Java SE 7开始,HotSpot VM就是Java规范的“参考实现”(RI,Reference Implementation)。也就是说,把HotSpot称为做“标准JVM”完全不为过。可参考:
Java Platform, Standard Edition 7 Reference Implementations
Java Platform, Standard Edition 8 Reference Implementations

当大家说起“Java性能如何如何”、“Java有多少种GC”、“JVM如何调优”云云,经常默认说的就是特指HotSpot VM。可见其“主流性”。(其实这不是件好事;具体到JVM实现才可以讨论的问题还是应该指明讨论是基于哪个实现)

(2)、简介

JDK8的HotSpot VM已经是以前的HotSpot VM 与JRockit VM的合并版,也就是传说中的HotRockit,只是产品里名字还是叫HotSpot VM。

HotSpot最初并非Sun公司开发的,而是由一家名为“LongviewTechnologies”的小公司设计的,甚至这款虚拟机一开始也不是为Java语言开发的,Sun公司注意到了这款虚拟机在JIT编译技术(Just In Time,即时编译技术)上有许多优秀的理念,在1997年收购了这家公司,获得了HotSpot VM。

HotSpot VM的最大特点,正如其名,就是热点代码探测能力。具体来说HotSpot VM的热点代码探测能力可以通过执行计数器找出最具有编译价值的代码,然后通知JIT编译器以方法为单位进行编译。如果一个方法被频繁调用,或方法中有效循环次数很多,将会分别触发标准编译和OSR(栈上替换)编译动作。通过编译器与解释器恰当地协同工作,可以在最优化的程序响应时间与最佳执行性能中取得平衡,而且无须等待本地代码输出才能执行程序,即时编译的时间压力也相对减小,这样有助于引入更多的代码优化技术,输出质量更高的本地代码。

JRockit VM曾经号称“世界上速度最快的Java虚拟机”(广告词,貌似J9 VM也这样说过),它是BEA公司在2002年从Appeal Virtual Machines公司收购的虚拟机。BEA公司将其发展为一款专门为服务器硬件和服务器端应用场景高度优化的虚拟机,由于专注于服务器端应用,它可以不太关注程序启动速度,因此JRockit内部不包含解析器实现,全部代码都靠即时编译器编译后执行。除此之外,JRockit的垃圾收集器和MissionControl服务套件等部分的实现,在众多Java虚拟机中也一直处于领先水平。

这个合并并不是简单地把JRockit的部分代码插进HotSpot里,而是把前者一些有价值的功能在后者里重新实现一遍。如移除PermGen、Java Flight Recorder、jcmd等都属于合并项目的一部分。

不过要留意的是,这里我说的HotSpot VM特指正常配置版,而不包括Zero / Shark版。Wikipedia那个页面上把后者称为Zero Port。用这个版本的人应该相当少,很多时候它的release版都build不成功…

2)、J9 VM

J9 VM是IBM开发的一个高度模块化的JVM。

(1)、简介

在许多平台上,IBM J9 VM都只能跟IBM产品一起使用。这不是技术限制,而是许可证限制。例如说在Windows上IBM JDK不是免费公开的,而是要跟IBM其它产品一起捆绑发布的;使用IBM Rational、IBM WebSphere的话都有机会用到J9 VM(也可以自己选择配置使用别的Java SE JVM)。

根据许可证,这种捆绑在产品里的J9 VM不应该用于运行别的Java程序…大家有没有自己“偷偷的”拿来跑别的程序IBM也没力气管(咳咳而在一些IBM的硬件平台上,很少客户是只买硬件不买配套软件的,IBM给一整套解决方案,里面可能就包括了IBM JDK。这样自然而然就用上了J9 VM。

所以J9 VM得算在主流里,虽然很少是大家主动选择的首选。

(2)、性能

J9 VM的性能水平大致跟HotSpot VM是一个档次的。有时HotSpot快些,有时J9快些。不过J9 VM有一些HotSpot VM在JDK8还不支持的功能,最显著的一个就是J9支持AOT编译和更强大的class data sharing。

3)、Zing VM

(1)、简介

Zing VM是一个由Azul Systems公司从Sun HoSpot VM fork出来的一个高性能JVM,可以运行在Linux/x86-64平台上。

Azul 公司为它重新写了一套GC,也修改了VM内的许多实现细节,所以从我们自己的角度看,与其说它是HotSpot VM的一个变种,还不如把它看作“一个全新的JVM、只是凑巧与HotSpot VM很像”更合适。

(2)、性能

在要求低延迟、快速预热等的场景里,Zing VM都会比HotSpot VM表现更好:

  • 支持内存大,GC STW时间短

Zing的C4 GC目前可以支持1TB的-Xmx,而且GC暂停时间仍然可以维持在< 10ms的范围里。实际上Zing现在能支持接近2TB的-Xmx,但我们还没能用来测试2TB场景的机器…据说再过一段时间这个测试服务器就要到货了。

  • 快速预热

Zing的ReadyNow!功能可以利用之前收集到的profile数据,引导JVM在启动后快速达到稳定的高性能水平,减少启动后从解释执行到JIT编译的等待时间。

  • 更全面的JVM监控

-Zing自带的ZVision / ZVRobot功能可以方便用户监控JVM的运行状态,从找出代码热点到对象分配监控、锁竞争监控等都可以做到。

  • 性能更优

最关键的是,Zing能让普通没有为GC之类的底层方向调优的Java应用享有低延迟、快速预热、易于监控的功能,为用户节省苦苦调优的精力和时间。这是Zing的主要价值——很多Java应用都可以通过长期努力在应用/框架层面优化来提升性能,但使用Zing的话就可以更多把精力集中在业务方面。

5、如何查看虚拟机的类型

运行如下命令即可:

java -version

java -version

参考文章