什么是 JVM? Java 虚拟机简介
Java虚拟机是一个程序,其目的是执行其他程序。 这是一个简单的想法,也是我们编码功夫最伟大的例子之一。 JVM 颠覆了当时的现状,并在今天继续支持编程创新。
JVM 是做什么的?
JVM 有两个主要功能:允许 Java 程序在任何设备或操作系统上运行(称为“一次编写,随处运行”原则),以及管理和优化程序内存。 当 Java 于 1995 年发布时,所有的计算机程序都是针对特定的操作系统编写的,程序内存由软件开发人员管理。 JVM 是一个启示。
JavaWorld / IDG
图 1. JVM 的高级视图。
拥有 JVM 的技术定义很有用,软件开发人员也有一种日常的思考方式。 让我们分解一下:
- 技术定义:JVM 是执行代码并为该代码提供运行时环境的软件程序的规范。 日常定义:JVM 是我们运行 Java 程序的方式。 我们配置设置,然后在执行过程中依靠 JVM 来管理程序资源。
当开发人员谈论 JVM 时,我们通常指的是在机器上运行的进程,尤其是服务器,代表和控制 Java 应用程序的资源使用。 将此与 JVM 规范进行对比,JVM 规范描述了构建执行这些任务的程序的要求。
JVM语言
虽然它曾经只适用于 Java,但 JVM 足够灵活和强大,可以支持当今的许多其他语言。 其中最受欢迎的是用于实时并发应用程序的 Scala 和动态类型脚本语言 Groovy。 另一个突出的例子是 Kotlin,它融合了面向对象和函数式风格。 所有这些都被认为是 JVM 语言,这意味着即使它们不是用 Java 编码的,程序员仍然可以访问 Java 库的庞大生态系统。
谁开发和维护 JVM?
JVM 被一些非常聪明的程序员广泛部署、大量使用和维护,包括公司和开源。 OpenJDK 项目始于 Sun Microsystems 决定开源 Java,并在 Oracle 的管理下继续进行。
垃圾收集
与运行中的 JVM 最常见的交互是检查堆和堆栈中的内存使用情况。 最常见的调整是对 JVM 的内存设置进行性能调整。
在 Java 之前,所有程序内存都由程序员管理。 在 Java 中,程序内存由 JVM 管理。 JVM 通过称为垃圾收集的过程管理内存,该过程不断识别并消除 Java 程序中未使用的内存。 垃圾回收发生在运行中的 JVM 中。
在早期,Java 因不像 C++ 那样“接近金属”而受到很多批评,因此也没有那么快。 垃圾收集过程尤其有争议。 从那时起,各种算法和方法被提出并用于垃圾收集。 通过持续的开发和优化,垃圾收集得到了极大的改进。 (自动内存管理也流行起来,并且是其他现代语言(如 JavaScript 和 Python)的共同特征。)
“接近金属”是什么意思?
当程序员说一种编程语言或平台“接近金属”时,我们的意思是开发人员能够以编程方式(通过编写代码)管理操作系统的内存。 从理论上讲,程序员可以通过规定使用多少以及何时丢弃来从我们的程序中获得更多性能。 在大多数情况下,将内存管理委派给高度精炼的进程(如 JVM)比自己进行管理会产生更好的性能和更少的错误。
JVM的三部分
可以说 JVM 分为三个方面:规范、实现和实例。 让我们考虑每一个。
JVM规范
首先,JVM 是一种软件规范。 JVM 规范以一种有点循环的方式强调其实现细节未在规范中定义,以便在其实现中实现最大的创造力:
要正确实现 Java 虚拟机,您只需要能够阅读
class
文件格式并正确执行其中指定的操作。
JS Bach 曾经类似地描述过创作音乐:
您所要做的就是在正确的时间触摸正确的键。
因此,JVM 所要做的就是正确运行 Java 程序。 听起来很简单,甚至可能从外面看起来很简单,但这是一项艰巨的任务,尤其是考虑到 Java 语言的强大功能和灵活性。
虚拟机
JVM 是一种以可移植方式运行 Java 类文件的虚拟机。 作为虚拟机意味着 JVM 是底层实际机器的抽象——例如运行程序的服务器。 不管实际存在什么操作系统或硬件,JVM 都会为程序在其中运行创建一个可预测的环境。 然而,与真正的虚拟机不同,JVM 不会创建虚拟操作系统。 将 JVM 描述为托管运行时环境或进程虚拟机会更准确。
JVM 实现
实施 JVM 规范会产生实际的软件程序,即 JVM 实施。 事实上,有许多 JVM 实现,既有开源的,也有专有的。 OpenJDK 的 HotSpot 是 JVM 参考实现。 它仍然是世界上经过最彻底尝试和测试的代码库之一。
HotSpot 可能是最常用的 JVM,但绝不是唯一的。 另一个有趣且流行的实现是 GraalVM,它具有高性能并通过 LLVM 规范支持其他传统的非 JVM 语言,如 C++ 和 Rust。 还有特定领域的 JVM,如嵌入式机器人 JVM、LeJOS
通常,您下载并安装 JVM 作为 Java 运行时环境 (JRE) 的捆绑部分。 JRE 是 Java 的磁盘部分,它生成正在运行的 JVM。
一个 JVM 实例
在 JVM 规范作为软件产品实施和发布后,您可以下载并作为程序运行。 下载的程序是 JVM 的一个实例(或实例化版本)。
大多数时候,当开发人员谈论“JVM”时,我们指的是在软件开发或生产环境中运行的 JVM 实例。 您可能会说,“嘿 Anand,该服务器上的 JVM 使用了多少内存?” 或者,“我无法相信我创建了一个循环调用并且堆栈溢出错误导致我的 JVM 崩溃。这是一个多么新手的错误!”
什么是软件规范?
软件规范(或规范)是一种人类可读的设计文档,描述了软件系统应该如何运行。 规范的目的是为工程师编写代码创建清晰的描述和要求。
JVM如何加载和执行类文件
我们已经讨论了 JVM 在运行 Java 应用程序中的作用,但它是如何发挥作用的呢? 为了运行 Java 应用程序,JVM 依赖于 Java 类加载器和 Java 执行引擎。
Java类加载器
Java 中的一切都是类,所有 Java 应用程序都是从类构建的。 一个应用程序可以包含一个类或数千个。 为了运行 Java 应用程序,JVM 必须将已编译的 .class 文件加载到可以访问它们的上下文中,例如服务器。 JVM 依靠其类加载器来执行此功能。
当你打字时 java classfile
,你是说:启动一个 JVM 并将指定的类加载到其中。
Java 类加载器是 JVM 的一部分,它将类加载到内存中并使它们可供执行。 类加载器使用延迟加载和缓存等技术使类加载尽可能高效。 也就是说,类加载不是(比方说)可移植运行时内存管理那样的史诗般的脑筋急转弯,因此这些技术相对简单。
每个 Java 虚拟机都包含一个类加载器。 JVM 规范描述了在运行时查询和操作类加载器的标准方法,但 JVM 实现负责实现这些功能。 从开发者的角度来看,底层的类加载器机制是一个黑盒子。
执行引擎
一旦类加载器完成了加载类的工作,JVM 就开始执行每个类中的代码。 执行引擎是处理此功能的 JVM 组件。 执行引擎对于运行的 JVM 是必不可少的。 事实上,出于所有实际目的,它就是 JVM 实例。
执行代码涉及管理对系统资源的访问。 JVM 执行引擎位于正在运行的程序(需要文件、网络和内存资源)和提供这些资源的操作系统之间。
系统资源可分为两大类:内存和其他所有资源。 回想一下,JVM 负责处理未使用的内存,而垃圾收集是执行该处理的机制。 JVM 还负责分配和维护开发人员认为理所当然的引用结构。 例如,JVM 的执行引擎负责获取类似 new
Java 中的关键字,并将其转换为特定于操作系统的内存分配请求。
除了内存之外,执行引擎还管理文件系统访问和网络 I/O 的资源。 由于 JVM 可跨操作系统互操作,因此这不是一项简单的任务。 除了每个应用程序的资源需求之外,执行引擎还必须响应每个操作系统环境。 这就是 JVM 能够处理野外需求的方式。
JVM 演进:过去、现在、未来
由于 JVM 是众所周知的具有标准化配置、监控和管理的运行时,因此它非常适合使用 Docker 和 Kubernetes 等技术进行容器化开发。 它也适用于平台即服务 (PaaS),并且有多种无服务器方法。 由于所有这些因素,JVM 非常适合微服务架构。
即将出现的另一个重要功能是 Project Loom,它旨在将虚拟线程引入 JVM。 虚拟线程能够在操作系统进程之上以更高的抽象进行并发。 虚拟线程能够在它们之间共享内存,从而潜在地极大地改进编码惯用语和性能。
结论
1995 年,JVM 引入了两个革命性的概念,这两个概念后来成为现代软件开发的标准票价:“一次编写,随处运行”和自动内存管理。 软件互操作性在当时是一个大胆的概念,但如今很少有开发人员会三思而后行。 同样,我们的工程先辈们必须自己管理程序内存,而我们这一代人是在垃圾收集的环境中长大的。
我们可以说 James Gosling 和 Brendan Eich 发明了现代编程,但在接下来的几十年里,还有成千上万的人在他们的想法的基础上不断完善和发展。 尽管 Java 虚拟机最初仅适用于 Java,但如今它已经发展为支持多种脚本和编程语言,包括 Scala、Groovy 和 Kotlin。 展望未来,很难看到 JVM 不再是开发领域的重要组成部分的未来。