# JVM的发展历史

# JVM与混合语言编程

Java虚拟机(JVM)最初设计是为了运行Java语言编写的程序,但是随着时间的发展,JVM已经成为了一个多语言平台,能够支持多种编程语言。只要这些语言能够被编译成符合JVM规范的字节码,它们就可以在JVM上运行。这主要得益于JVM的强大功能和灵活性,它不仅仅局限于执行Java代码。

image-20250803225917054

  • java: 可能不是最好的,但一定是用的人最多的
  • Groovy:Groovy是一种基于Java平台的动态语言,具有类似Java的语法,但更加简洁。它可以直接与Java代码互操作,非常适合快速应用程序开发、测试脚本编写以及构建自动化工具如Gradle。
  • Kotlin:Kotlin是一种静态类型的编程语言,可以编译为Java字节码、JavaScript源码或本地代码。它完全兼容Java,并且可以与Java代码无缝集成。Kotlin主要用于Android应用开发、Web开发、服务器端应用等。
  • Jython: 是Python语言的一种实现,它编译Python代码为Java字节码,使得Python程序能够在JVM上运行。Jython有助于让Python开发者能够利用丰富的Java生态系统
  • Scala:Scala融合了面向对象和函数式编程的特性,旨在提供比Java更好的并发性支持。它生成的字节码可以在任何标准的Java平台上运行,因此可以充分利用现有的Java库和框架。Scala常用于大数据处理框架如Apache Spark中

# JVM发展历史

# Sun Classic

虚拟机始祖,世界上第一款商用Java虚拟机,Sun发布JDK 1.0,Java语言首次拥有了商用的正式运行环境,这个JDK中所带的虚拟机就是Classic VM,

  • Sun Classic VM:这是Java首次拥有的商用正式运行环境中的核心组件。Classic VM是Java代码执行的主要引擎,它负责加载、验证、执行字节码等任务。
  • 纯解释器方式:在最开始,Classic VM只能通过解释器来逐行解释并执行Java字节码。这意味着每一条指令都需要被实时翻译成机器语言,然后由计算机执行,这种方式效率较低,尤其是与编译型语言如C/C++相比时更为明显。
  • 即时编译器(JIT Compiler)外挂:为了提升性能,可以将即时编译器作为外部插件添加到Classic VM中。然而,这个过程并不完美。一旦即时编译器被激活,它就会接管整个执行流程,使得解释器无法继续工作。这种情况下,即时编译器必须对所有的方法和代码行进行编译,无论它们是否频繁被执行或值得优化。
  • 解释器和编译器不能配合工作:由于技术限制,当时的Classic VM无法同时使用解释器和即时编译器。这就导致了一个问题:即使某些代码片段执行频率很低,不适合编译优化,但为了保证程序的正常运行,编译器也得对其进行编译。这不仅浪费了时间,还可能因为过度优化而导致不必要的资源消耗。
  • 执行效率低下:“Java语言很慢”的印象主要是因为在这一阶段,尽管采用了即时编译技术,但由于上述原因,其执行效率仍远不及传统的编译型语言如C/C++。这是因为编译器不敢采用耗时较长的高级优化技术,以避免增加程序响应时间。

# Exact VM

是Sun Microsystems在1998年发布的一款Java虚拟机,它是对早期Classic VM的一个重要改进版本。Exact VM引入了精确的垃圾回收机制,这是其名字“Exact”的由来。以下是对Exact VM的一些详细介绍:

  • 精确的垃圾收集:与之前的Classic VM不同,Exact VM能够准确地识别堆中的对象引用,这意味着它能更有效地进行内存管理和垃圾回收。这种能力使得Exact VM可以更好地处理复杂的对象图和循环引用的问题。
  • 改进的性能:通过更高效的内存管理和优化后的即时编译器(JIT Compiler),Exact VM在执行效率上有了显著提升。这有助于减少由于频繁的垃圾回收操作导致的应用程序暂停时间,并提高了整体性能。
  • 更好的多线程支持:Exact VM增强了对多线程编程的支持,包括更有效的同步机制和改进的线程调度策略。这些改进对于编写并发应用程序非常重要。
  • 平台独立性增强:虽然所有的Java虚拟机都致力于提供“一次编写,到处运行”的能力,但Exact VM在此基础上做了更多工作,以确保其可以在不同的操作系统和硬件平台上提供一致的行为和性能表现。

“准确式内存管理”(Exact Memory Management) 是如何工作的,以及它相比 Classic VM 的 句柄(Handle)机制 有哪些优势?

在 JVM 中,程序访问对象有两种主要方式:

  1. 句柄访问(Handle-based Access)
  2. 直接指针访问(Direct Pointer Access)

我们通过对比来理解它们。

# Classic VM:句柄访问

在早期的 Classic VM 中,由于虚拟机无法“准确”知道内存中某个数值是“引用”还是“普通整数”,因此采用了 句柄池(Handle Table) 的方式来间接访问对象。

栈(Stack)          堆(Heap)
┌─────────────┐     ┌─────────────────┐
│  objRef     │----→│ 句柄池 (Handle)  │
└─────────────┘     │ ┌─────────────┐ │
                    │ │ 对象指针      │ │ → 指向实际对象
                    │ └─────────────┘ │
                    │ ┌─────────────┐ │
                    │ │ 对象类型信息   │ │
                    │ └─────────────┘ │
                    └─────────────────┘
                                      ↓
                                ┌─────────────┐
                                │ 实际对象数据 │
                                └─────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14

工作流程:

  • 栈中的 objRef 不直接指向对象,而是指向一个 句柄表中的条目
  • 句柄表中保存两个信息:
    • 指向对象实际内存地址的指针
    • 指向对象类型信息(如类元数据)的指针
  • 对象在堆中移动(比如垃圾回收时被压缩),只需更新句柄表中的指针,而栈中的引用(objRef)和句柄本身不变。

缺点:

  • 每次访问对象都要

    两次内存访问:

    1. 先查句柄表
    2. 再通过句柄中的指针找到真实对象
  • 多了一层间接,性能开销大

# Exact VM :直接指针访问 + 准确式内存管理

Exact VM 引入了 准确式内存管理 —— 虚拟机 明确知道哪些内存位置存储的是“引用类型”。

这意味着:

虚拟机可以区分:内存中某个值是“整数 123456”还是“指向地址 123456 的对象引用”。

栈(Stack)          堆(Heap)
┌─────────────┐     ┌─────────────┐
│  objRef     │----→│ 实际对象数据 │
└─────────────┘     └─────────────┘
1
2
3
4
  • objRef 直接指向对象在堆中的地址。
  • 不再需要句柄表,访问对象只需一次指针跳转。

但问题来了:如果对象被 GC 移动了怎么办?

  • 原来对象在地址 123456
  • GC 后被移动到 654321
  • 栈中所有引用 123456 都要改成 654321

如果虚拟机 不知道哪些内存是引用,它就不敢乱改——万一把一个整数 123456 错误地改成 654321,程序就崩溃了!但 Exact VM 可以做到

Exact VM 虽然技术先进,但生命周期很短,很快被 HotSpot VM 取代

# HotSpot VM

相信所有Java程序员都听说过HotSpot虚拟机,它是Sun/OracleJDK和OpenJDK中的默认Java虚拟机,也是目前使用范围最广的Java虚拟机

1.1.3至今默认VM

2.Logview公司设计,被sun收购

3.编译器与解释器恰当地协同工作

4.可以在最优化的程序响应时间与最佳执行性能中取得平衡

5.只有Hotspot才有方法区(永久代)

# JRockit VM

  • BEA公司,2008被Oracle收购
  • 最快的JVM
  • JRockit专注于服务器端
  • JRockit不包含解释器,只包含编译器

# IBM J9 VM

  • IBM Technology For Java Virtual Machine
  • 简称IT4J 内部代号:J9
  • J9与Hotspot定位接近,通用型JVM
  • “最快”的JVM,只在对IBM自家的产品优化良好
  • 2017年J9开源,Open J9