HotSpot VM 是 Sun JDK 和 OpenJDK 中所带的虚拟机,也是目前使用范围最广的 Java 虚拟机。它在 Java 技术中起着至关重要的作用,其历史可追溯至 1997 年 Sun 公司收购设计它的 “Longview Technologies” 小公司。HotSpot VM 最初并非为 Java 语言开发,而是来源于 Strongtalk VM,而 Strongtalk VM 中的许多技术又源于一款支持 Self 语言实现 “达到 C 语言 50% 以上执行效率” 目标的虚拟机。HotSpot VM 一开始就是准确式 GC,其名称中的 HotSpot 指的是热点代码探测技术。该技术可以通过执行计数器找出最具有编译价值的代码,然后通知 JIT 编译器以方法为单位进行编译。如果一个方法被频繁调用,或方法中有效循环次数很多,将会分别触发标准编译和 OSR(栈上替换)编译动作。
HotSpot VM 的核心代码包括多个模块,如 adlc(平台描述文件编译器)、asm(汇编器接口)、c1(client 编译器)、ci(动态编译器的公共服务)、classfile(类文件的处理)、code(动态生成的代码的管理)、compiler(从 VM 调用动态编译器的接口)、gc_implementation(GC 的实现,包括 concurrentMarkSweep、g1、parallelScavenge、parNew、shared 等)、gc_interface(GC 接口)、interpreter(解释器,包括模板解释器和 C++ 解释器)、libadt(一些抽象数据结构)、memory(内存管理相关)、oops(HotSpot VM 的对象系统的实现)、opto(server 编译器)、precompiled、prims(HotSpot VM 的对外接口,包括部分标准库的 native 部分和 JVMTI 实现)、runtime(运行时支持库,包括线程管理、编译器调度、锁、反射等)、services(主要是用来支持 JMX 之类的管理功能的接口)、shark(基于 LLVM 的 JIT 编译器,官方版未使用)、trace 和 utilities(一些基本的工具类)。
HotSpot VM 采用分代垃圾收集器,基于多数分配对象存活时间短且存活时间久的对象很少引用存活时间短的对象这一观察事实,将堆分为两个物理区空间,即新生代和老年代,并根据各自特点选择不同收集器以提升垃圾回收效率。在 2006 年 JavaOne 大会上,Sun 公司宣布将 Java 开源,并在随后一年将 JDK 各个部分包括 HotSpot VM 在 GPL 协议下公开源码,建立了 OpenJDK。2008 年和 2009 年,Oracle 公司分别收购 BEA 公司和 Sun 公司,拥有了 JRockit VM 和 HotSpot VM 两款优秀虚拟机,并计划在发布 JDK 8 时完成整合工作,在 HotSpot 的基础上移植 JRockit 的优秀特性。
HotSpot VM 的起源
HotSpot VM 最初是由一家名为 “Longview Technologies” 的小公司设计。它的起源可以追溯到对编程语言 Self 的支持,为了实现 “达到 C 语言 50% 以上的执行效率” 这一目标而设计的虚拟机,其中相当多的技术被 HotSpot VM 所继承。Sun 公司注意到了这款虚拟机在 JIT 编译上的优秀理念和实际效果,于 1997 年收购了 Longview Technologies 公司,从而获得了 HotSpot VM。此后,HotSpot VM 在 Java 虚拟机领域逐渐崭露头角,成为目前使用范围最广的 Java 虚拟机。在 2006 年,Sun 公司宣布将 Java 开源,并在此基础上建立了 OpenJDK,HotSpot VM 便成为了 Sun JDK 和 OpenJDK 两个实现极度接近的 JDK 项目的共同虚拟机。2008 年和 2009 年,Oracle 公司分别收购了 BEA 公司和 Sun 公司,进一步推动了 HotSpot VM 的发展和整合。
HotSpot VM 的核心代码模块
HotSpot VM 的核心代码位于 vm 模块下,包括多个子模块。其中,adlc 模块是平台描述文件的编译器;asm 模块是汇编器接口;c1 模块是 client 编译器;ci 模块是动态编译器的公共服务及从动态编译器到 VM 的接口;classfile 模块负责类文件的处理,包括类加载和系统符号表等;code 模块管理动态生成的代码;compiler 模块是从 VM 调用动态编译器的接口;gc_implementation 模块包含了各种 GC 的实现,如 concurrentMarkSweep、g1、parallelScavenge、parNew 等;gc_interface 模块是 GC 接口;interpreter 模块包括解释器,如 “模板解释器” 和 “C++ 解释器”;libadt 模块包含一些抽象数据结构;memory 模块负责内存管理相关事宜;oops 模块是 HotSpot VM 的对象系统的实现;opto 模块是 server 编译器;precompiled 模块、prims 模块主要负责提供外部程序访问 JVM 内部信息的对外接口,包括 JNI、JVM、JVMTI 和 Perf 等;runtime 模块是运行时支持库,涵盖线程管理、编译器调度、锁、反射等;services 模块主要用于支持 JMX 之类的管理功能接口;shark 模块是基于 LLVM 的 JIT 编译器,但官方版未使用;trace 模块和 utilities 模块包含一些基本的工具类。
HotSpot VM 的垃圾收集器
HotSpot VM 拥有多种垃圾收集器,以满足不同的应用场景需求。
在新生代垃圾收集器中,Serial 垃圾收集器是单线程的,采用复制算法,在进行垃圾回收时会暂停其他所有的工作线程,适合所需内存较小的客户端应用。ParNew 垃圾收集器是 Serial 的多线程版本,除了使用多线程进行垃圾回收之外,其他行为和 Serial 收集器相同,主要应用在服务端模式下。Parallel Scavenge 收集器也是用于年轻代的回收器,采用多线程并发回收,可以通过设置参数来控制 GC 的最大停顿时间,以达到吞吐量可控的目标,适合在后台运算没有太多交互的任务。
在老年代垃圾收集器中,Serial Old 是 Serial 垃圾收集器的老年代版本,采用单线程和标记 - 整理算法。Parallel Old 垃圾收集器是 Parallel Scavenge 收集器的老年代版本,使用多线程和 “标记 - 整理” 算法。CMS 收集器是基于标记 - 清除算法的,以追求收集速度为目标,适合追求垃圾收集速度的服务器上,但会牺牲系统的吞吐量。G1 垃圾收集器既可以回收新生代,也可以回收老年代,在 JDK9 中成为 HotSpot VM 默认的垃圾收集器。
HotSpot VM 的开源历程
在 2006 年底,Sun 公司将 JDK 的各个部分(其中包括 HotSpot VM)在 GPL 协议下公开了源码,并在此基础上建立了 OpenJDK。这样,HotSpot VM 便成为了 Sun JDK 和 OpenJDK 两个实现极度接近的 JDK 项目的共同虚拟机。此后,HotSpot VM 的开源项目不断发展和完善,吸引了众多开发者的参与和贡献。
HotSpot VM 与 JRockit VM 的整合
2008 年和 2009 年,Oracle 公司分别收购了 BEA 公司和 Sun 公司,从而同时拥有了 JRockit VM 和 HotSpot VM 两款虚拟机。目前 Oracle 公司在推进这两款虚拟机的整合工作,使之优势互补。JDK8 的 HotSpot VM 已经是以前的 HotSpot VM 与 JRockit VM 的合并版,例如移除 PermGen、Java Flight Recorder、jcmd 等都属于合并项目的一部分。虽然产品里名字还是叫 HotSpot VM,但实际上融合了 JRockit VM 的一些有价值的功能。
HotSpot VM 作为目前使用范围最广的 Java 虚拟机,其起源于一家小公司的设计,后被 Sun 公司收购并不断发展壮大。在开源历程中,它成为了 Sun JDK 和 OpenJDK 的共同虚拟机,吸引了众多开发者的贡献。同时,HotSpot VM 还与 JRockit VM 进行整合,以实现优势互补,为 Java 开发者提供更强大的虚拟机性能和功能。