Java 开发工具包 (JDK)、Java 虚拟机 (JVM) 和 Java 运行时环境 (JRE) 共同构成了强大的 Java 和Jakarta EE平台组件三重奏,用于开发和运行 Java 应用程序。它们一起工作,让开发人员构建和运行 Java 程序。之前我已经介绍过JDK和JVM。 在本快速概述中,您将了解 JRE,它是 Java 的运行时环境。
实际上,运行时环境是一个旨在运行其他软件的软件。JRE作为Java的运行环境,包含Java类库、Java类加载器和Java虚拟机。在这个系统中:
我们将在接下来的讨论中更深入地探讨这些组件如何协同工作。
从安装的角度来看,每当您下载 JDK时,它都会包含一个版本兼容的 JRE,并且该 JRE 将包含一个默认的 JVM。您还可以从 JDK 中单独下载 JRE,并且可以从多种 JVM 中进行选择。默认值适用于大多数实现,尤其是当您刚开始使用 Java 时。
目录
软件程序需要执行,而要做到这一点,它需要一个运行环境。过去,大多数软件都使用操作系统(OS)作为运行环境。该程序在其所在的任何计算机内运行,并直接依赖操作系统设置来访问资源;内存、磁盘访问和网络访问等资源。Java 运行时环境改变了这一切,至少对于 Java 程序来说是这样。对于 Java 和其他基于 JVM 的语言,JRE 在操作系统和实际程序之间创建了一个中介。JRE 加载类文件并启动虚拟机(JVM),以确保在许多操作系统中以一致的形式访问内存和其他系统资源。
当它第一次被引入时,Java 的“一次编写,随处运行”原则被认为是革命性的。如今,它已被许多软件系统采用作为规范,包括JavaScript和Python。
我们可以将软件视为位于系统硬件之上的一系列层。每一层都提供其上层将使用(和需要)的服务。Java 运行时环境产生了 JVM,它是一个运行在计算机操作系统之上的软件层,提供特定于 Java 的附加服务。图 1 说明了这种布置。
图 1. Java 运行时环境生成 JVM。
JRE 平滑了操作系统的多样性,确保 Java 程序无需修改即可在几乎任何操作系统上运行。它还提供增值服务。自动内存管理是JRE最重要的服务之一,确保程序员不必手动控制内存的分配和重新分配。
简而言之,JRE 是 Java 的一种元操作系统,以及其他JVM 语言(如 Scala 和 Groovy)。这是一个典型的抽象示例,将底层操作系统抽象为运行 Java 应用程序的一致平台。
Java虚拟机是一个运行软件系统,负责执行实时Java程序。JRE 是磁盘上的软件组件,它获取已编译的 Java 代码(该代码是使用 JDK 编译的),将其与所需的库结合起来,然后启动 JVM 来执行它。
JRE 包含 Java 程序运行所需的库和软件。例如,Java 类加载器是 JRE 的一部分。这个重要的软件将编译后的 Java 代码加载到内存中,并将代码连接到适当的 Java 类库(这个过程称为链接)。
在我刚才描述的分层视图中,JVM 是由 JRE 创建的。从包的角度来看,JRE 包含 JVM,如图 2 所示。JVM 是 JRE 的一部分 — 它是 JRE 创建的用于托管程序的活动的运行部分。JRE 获取静态资产并将它们转换为托管正在运行的程序的正在运行的 JVM。
图 2. 分层架构视图显示 JRE 包含 JVM、类加载器和 Java 类库。
虽然 JRE 有一个概念性的一面,但在现实世界中,它只是安装在计算机上的软件,其目的是运行 Java 程序。作为开发人员,您主要使用 JDK 和 JVM,因为这些是您用来开发和运行 Java 程序的平台组件。作为 Java 应用程序用户,您将更多地参与 JRE,它允许您运行这些程序。
Java 9重构了 Java 平台,因此 JRE 现在只能作为 JDK 的一部分使用。当您想要使用JLink交付消费者应用程序时,您可以将捆绑的 JRE 与您的应用程序一起交付。这样的捆绑包包含运行程序所需的所有组件。出于我们的目的,我们将在 JDK 中使用 JRE。您可以从 Oracle 的 Java SE 页面下载适合您的系统的最新 JDK 。Windows 和 macOS 具有自动安装程序,可以管理详细信息(例如设置路径)。在 Linux 上,一个不错的选择是使用SDKMan。无论如何,您都需要从命令行获取 JRE,以便可以使用该java命令。
Java 运行时环境会针对每个新版本的 Java 进行更新,其版本号与 Java 平台版本控制系统保持一致,例如 JRE 1.19 运行Java 19。
许多计算机运行为 Java SE 开发的 JRE,它能够运行任何 Java 应用程序,无论它是如何开发的。大多数移动设备都附带有适用于 Java ME 的 JRE,该 JRE 已预安装在移动设备上,并且不可供下载。展望未来,通过 JLink 与自己的 JRE 捆绑的应用程序将成为常态。
下载 JDK 后,您可以通过在命令行上键入 与包含的 JRE 进行交互 java -version,这将告诉您安装的版本。(在 POSIX 系统上,您始终可以使用命令检查安装位置which java。)
JRE 在开发阶段并不是很引人注目,它主要只是在您选择的操作系统或 IDE 中运行您的程序。它在 DevOps 和系统管理中扮演着更重要的角色,因为 JRE 用于监视和配置。
基本上,JRE 提供了用于配置和控制 Java 应用程序特性的“旋钮”。内存使用就是一个典型的例子,它是系统管理的基础。虽然内存使用始终很重要,但它在云配置中至关重要,而 DevOps 是一种基于云的构建和运行软件的方法。如果您在 DevOps 环境中工作,或者有兴趣扩展到 DevOps,那么最好了解 Java 内存如何工作以及如何在 JRE 中对其进行监控。
DevOps是一个相对较新的术语,它描述了几十年来一直存在的东西,即开发和运营之间的互操作性。从这个意义上说,devops只是一种更新的方式来描述过去所谓的操作或系统管理。与系统管理员一样,devops 的一个重要方面是管理执行软件所需的系统。管理 JRE 是管理运行 Java 应用程序的系统的一部分。
Java 内存由三个部分组成:堆、栈和元空间(以前称为 permgen)。
在 Java 8 之前,元空间被称为permgen。除了是一个更酷的名字之外,元空间对于开发人员与 Java 内存空间交互的方式也是一个重大改变。以前,您可以使用该命令java -XX:MaxPermSize来监视 permgen 空间的大小。从 Java 8 开始,Java 会自动增加元空间的大小,以满足程序的元需求。Java 8 还引入了一个新标志 ,MaxMetaspaceSize您可以使用它来限制元空间大小。
堆空间是Java内存系统中最动态的部分。您可以使用-Xms和-Xmx标志来告诉 Java 启动堆有多大,以及允许它变成多大。了解如何根据特定程序需求调整这些标志是 Java 内存管理的一个重要方面。理想的情况是使堆足够大以获得最有效的垃圾收集。也就是说,您希望留出足够的内存来让程序运行,但又不希望内存过大。
堆栈空间是函数调用和变量引用排队的地方。堆栈空间是Java 编程中第二个最臭名昭著的异常的来源:StackOverflowError(第一个是 NullPointerException )。堆栈溢出异常表明您已经用完了堆栈空间,因为保留了太多堆栈空间。通常,当一个或多个方法以循环方式相互调用时,就会出现堆栈溢出,从而将越来越多的函数调用投入到堆栈中。
您可以使用-Xss开关来配置堆栈起始大小。然后堆栈根据程序的需要动态增长。
虽然应用程序监视是 JVM 的一项功能,但 JRE 提供了配置选项,这是监视的必要基线。有多种工具可用于监控 Java 应用程序,从经典工具(如 Unix 命令top)到复杂的远程监控解决方案(如 Oracle 基础设施监控)。
在这些选项之间是可视化分析器,例如VisualVM,它允许检查正在运行的 JVM。这些工具可以跟踪热点和内存泄漏,以及监视系统中的总体内存消耗。
Java 运行时环境是加载 Java 应用程序以供 JVM 执行的磁盘上程序。下载JDK时默认包含一个JRE,每个JRE都包含核心Java类库、Java类加载器和JVM。了解 JVM、JDK 和 JRE 如何交互很有帮助,尤其是在云和 DevOps 环境中工作时。在这些环境中,JRE 在监视和配置方面比在传统 Java 应用程序开发中发挥更强大的作用。