Java Virtual Machine 简明教程

JVM (Java Virtual Machine) Architecture

What is JVM (Java Virtual Machine)?

JVM (Java Virtual Machine) 是一个虚拟机,一个有自己的 ISA、内存、栈、堆等的抽象计算机。它在主机操作系统上运行,并在其上提出对资源的需求。

JVM (Java Virtual Machine) 是规范并且可以有不同的实现,只要它们符合规范。规范可以在以下链接中找到 − https://docs.oracle.com

Oracle 有自己的 JVM 实现(称为 HotSpot JVM),IBM 也有自己的实现(例如 J9 JVM)。

规范中定义的操作如下(来源 − Oracle JVM 规范)

  1. The 'class' file format

  2. Data types

  3. Primitive types and values

  4. Reference types and values

  5. Run-time data areas

  6. Frames

  7. Representation of objects

  8. Floating-point arithmetic

  9. Special methods

  10. Exceptions

  11. Instruction set summary

  12. Class libraries

  13. Public design, private implementation

JVM (Java Virtual Machine) Architecture

HotSpot JVM 3 的架构如下 −

architecture

执行引擎包括垃圾收集器和 JIT compiler。JVM 有两种版本 - clientserver。它们都共享相同的运行时代码,但是使用的 JIT 不同。稍后我们将详细了解这点。用户可以通过指定 JVM 标志 -client 或 -server 来控制使用什么版本。服务器 JVM 旨在用于服务器上的长时间运行的 Java 应用程序。

JVM 有 32 位和 64 位版本。用户可以通过在 VM 参数中使用 -d32 或 -d64 指定要使用的版本。32 位版本只能寻址最多 4G 的内存。随着关键应用程序在内存中维护大型数据集,64 位版本满足了这一需求。

Components of JVM (Java Virtual Machine) Architecture

以下是 JVM(Java 虚拟机)架构的主要组件:

1. Class Loader

JVM 以动态方式管理加载、链接和初始化类和接口。在加载过程中,JVM finds the binary representation of a class and creates it.

在链接过程中,loaded classes are combined into the run-time state of the JVM so that they can be executed during the initialization phase。JVM 主要使用存储在运行时常量池中的符号表进行链接过程。初始化实际上包括 executing the linked classes

以下是类加载器的类型:

  1. BootStrap class loader :该类加载器位于类加载器层次结构的顶部。它加载 JRE lib 目录中的标准 JDK 类。

  2. Extension class loader :该类加载器位于类加载器层次结构的中间,是引导类加载器的直接子类,并加载 JRE lib\ext 目录中的类。

  3. Application class loader :该类加载器位于类加载器层次结构的底部,是应用程序类加载器的直接子类。它加载 CLASSPATH ENV 变量指定的 jar 和类。

2. Linking and Initialization

链接过程包括以下三个步骤:

  1. Verification − 由字节码验证器完成,以确保生成的 .class 文件(字节码)有效。如果不是,则会抛出一个错误,并且链接进程会停止。

  2. Preparation − 为类的所有静态变量分配内存,并使用默认值对其进行初始化。

  3. Resolution − 将所有符号内存引用替换为原始引用。要实现此目的,将使用类方法区运行时常量存储器中的符号表。

Initialization 是类加载过程的最后阶段。静态变量被分配原始值,并且执行静态块。

3. Runtime Data Areas

JVM 规范定义了程序执行期间所需的某些运行时数据区域。其中一些在 JVM 启动时创建。其他一些是线程局部的,并且仅在创建线程时创建(并在线程被销毁时销毁)。这些如下所示:

它是每个线程的局部变量,并且包含线程当前正在执行的 JVM 指令的地址。

它是每个线程的局部变量,并且在方法调用期间存储参数、局部变量和返回地址。如果线程需要的堆栈空间超过允许的最大值,可能会发生 StackOverflow 错误。如果堆栈可以动态扩展,它仍然可以引发 OutOfMemoryError。

它是所有线程共享的,并且包含运行时创建的对象、类元数据、数组等。它在 JVM 启动时创建,并在 JVM 关闭时销毁。你可以使用某些标志控制你的 JVM 从操作系统请求的堆大小(稍后会详细介绍)。必须小心不要请求过少或过多的内存,因为这会产生重要的性能影响。此外,GC 管理此空间,并会不断删除死对象以释放空间。

此运行时区域对所有线程都是通用的,并且在 JVM 启动时创建。它存储每类结构,例如常量池(稍后会详细介绍)、构造函数和方法的代码、方法数据等。JLS 未指定是否需要对该区域进行垃圾回收,因此 JVM 的实现可能会选择忽略 GC。此外,这可能会或可能不会根据应用程序的需求进行扩展。JLS 没有强制规定任何相关内容。

JVM 维护一个每类/每类型数据结构,它在链接已加载的类时充当符号表(它扮演的众多角色之一)。

当一个线程调用一个本地方法时,它就会进入一个新世界,其中 Java 虚拟机的结构和安全限制不再妨碍它的自由。本地方法可能会访问虚拟机的运行时数据区域(它取决于本地方法接口),但也可能执行它想要做的任何其他操作。

4. Execution Engine

执行引擎负责执行字节码,它有三个不同的组件:

JVM 管理 Java 中对象的整个生命周期。一旦创建了一个对象,开发人员就不需要再担心它了。如果对象变成死对象(即不再引用它),它将通过串行 GC、CMS、G1 等多种算法之一从堆中弹出。

在 GC 过程中,对象在内存中移动。因此,在该进程进行时,不能使用那些对象。整个应用程序必须在整个进程持续时间内停止。这种暂停被称为“停止世界”暂停,并且开销很大。GC 算法的首要目标是减少此时间。

解释器解释字节码。它能快速解释代码,但执行速度较慢。

JIT 表示 Just-In-Time。JIT 编译器是 Java 运行时环境的主要部分,它在运行时编译字节码为机器码。

5. Java Native Interface (JNI)

Java 本机接口 (JNI) 与对执行至关重要的本机方法库进行交互。

6. Native Method Libraries

本机方法库是 C 和 C++ 库(本机库)的集合,对执行至关重要。