JVM Java Virtual Machine 是什么?怎么用 JVM 调优 Java 应用性能?

文章导读
上一个 测验 下一个 什么是 JVM (Java Virtual Machine)? JVM (Java Virtual Machine) 是一个虚拟机,它是一个抽象计算机,具有自己的指令集体系结构(ISA)、内存、栈、堆等。它运行在宿主操作系统上,并向其提出资源需求。
📋 目录
  1. 什么是 JVM (Java Virtual Machine)?
  2. JVM (Java Virtual Machine) 架构
  3. JVM(Java 虚拟机)架构的组件
A A

JVM (Java Virtual Machine) 架构



上一个
测验
下一个

什么是 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 Specs)

  • 'class' 文件格式
  • 数据类型
  • 原始类型和值
  • 引用类型和值
  • 运行时数据区
  • 对象的表示
  • 浮点运算
  • 特殊方法
  • 异常
  • 指令集摘要
  • 类库
  • 公共设计,私有实现

JVM (Java Virtual Machine) 架构

HotSpot JVM 3 的架构如下图所示 −

Architecture

执行引擎包括垃圾收集器和 JIT 编译器。JVM 有两种变体 − clientserver。两者共享相同的运行时代码,但使用的 JIT 不同。我们稍后将详细了解这一点。用户可以通过指定 JVM 标志 -client 或 -server 来控制使用哪种变体。server JVM 专为服务器上长时间运行的 Java 应用程序而设计。

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

JVM(Java 虚拟机)架构的组件

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

1. Class Loader

JVM 以动态方式管理类和接口的加载、链接和初始化过程。在加载过程中,JVM 找到类的二进制表示并创建它。

在链接过程中,已加载的类被合并到 JVM 的运行时状态中,以便在初始化阶段执行。 JVM 主要使用存储在运行时常量池中的符号表来进行链接过程。初始化包括实际执行已链接的类

以下是 class loader 的类型:

  • BootStrap class loader:这是 class loader 层次结构的最顶层。它加载 JRE 的 lib 目录中的标准 JDK 类。
  • Extension class loader:这是 class loader 层次结构的中层,是 bootstrap class loader 的直接子加载器,它加载 JRE 的 lib\ext 目录中的类。
  • Application class loader:这是 class loader 层次结构的最底层,是 application class loader 的直接子加载器。它加载由 CLASSPATH ENV 变量指定的 jars 和类。

2. Linking and Initialization

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

  • Verification − 这由 Bytecode verifier 执行,以确保生成的 .class 文件(字节码)有效。如果无效,则抛出错误并停止链接过程。
  • Preparation − 为类的所有静态变量分配内存,并用默认值初始化它们。
  • Resolution − 将所有符号内存引用替换为原始引用。为实现这一点,使用类的方法区域中的运行时常量内存中的符号表。

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

3. Runtime Data Areas

JVM 规范定义了程序执行期间所需的某些运行时数据区域。其中一些在 JVM 启动时创建。其他的是线程本地的,仅在线程创建时创建(线程销毁时销毁)。以下是这些区域 −

PC (Program Counter) Register

它是每个线程本地的,包含线程当前执行的 JVM 指令的地址。

Stack

它是每个线程本地的,用于在方法调用期间存储参数、局部变量和返回地址。如果线程要求超过允许的栈空间,则可能发生 StackOverflow 错误。如果栈是动态可扩展的,仍可能抛出 OutOfMemoryError。

Heap

它在所有线程之间共享,包含运行时创建的对象、类的元数据、数组等。它在 JVM 启动时创建,并在 JVM 关闭时销毁。您可以使用某些标志(稍后详述)控制 JVM 从 OS 请求的 heap 量。需要注意不要要求过少或过多的内存,因为这会影响性能。此外,GC 管理此空间并持续移除死对象以释放空间。

Method Area

此运行时区域对所有线程是通用的,在 JVM 启动时创建。它存储每个类的结构,如常量池(稍后详述)、构造函数和方法的代码、方法数据等。JLS 未指定此区域是否需要垃圾回收,因此 JVM 实现可能选择忽略 GC。此外,此区域可能根据应用程序需求扩展或不扩展。JLS 未对此做出规定。

Run-Time Constant Pool

JVM 维护一个每个类/每个类型的數據结构,在链接已加载的类时充当符号表(这是其众多角色之一)。

Native Method Stacks

当线程调用 native method 时,它进入一个新世界,在这个世界中,Java 虚拟机的结构和安全限制不再限制其自由。Native method 很可能可以访问虚拟机的运行时数据区域(取决于 native method interface),但也可以做其他任何事情。

4. Execution Engine

Execution engine 负责执行字节码,它有三个不同组件:

Garbage Collection

JVM 管理 Java 中对象的整个生命周期。一旦对象创建,开发者无需再担心它。如果对象变为死对象(即不再有引用指向它),GC 将使用多种算法之一(如 serial GC、CMS、G1 等)将其从 heap 中移除。

另读: Java 中的 Garbage Collection

在 GC 过程中,对象在内存中移动。因此,在过程进行期间,这些对象不可用。整个应用程序必须在过程持续时间内停止。这种暂停称为 'stop-the-world' 暂停,是巨大的开销。GC 算法的主要目标是减少此时间。

Interpreter

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

JIT Complier

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

5. Java Native Interface (JNI)

Java Native Interface (JNI) 与 native method 库交互,这些库对执行至关重要。

6. Native Method Libraries

Native method libraries 是 C 和 C++ 库(native libraries)的集合,这些库对执行至关重要。