JVM体系结构讲解

原文:https://dzone.com/articles/jvm-architecture-explained
作者:Jackson Joseraj
译者:Oopsguy

每一个Java开发人员都知道字节码是由JRE(Java Runtime Environment)执行的。但是很少有人知道JREJava虚拟机(JVM)的实现,它分析字节码,解释代码并执行。了解JVM的体系结构,对于作为一名开发人员来说是非常重要的。因为它使我们能够更加高效地编写代码。在本文中,我们将更加深入了解Java中的JVM体系结构以及JVM的各种不同组件

什么是JVM

虚拟机是物理机器的软件实现。Java的开发遵循WORA(一次编写随处运行)理念,它运行在VM(虚拟机)上。编译器将Java文件编译成Java.class文件,之后,将.class文件输入到JVM中,加载并执行该类文件。下图是JVM的体系结构:

JVM体系结构图

JVM体系结构讲解

JVM是如何工作的?

如上面的体系结构图所示,JVM分为三个主要的子系统:

  1. 类加载器子系统
  2. 运行时数据区
  3. 执行引擎

1、类加载器子系统

Java的动态类加载功能是由类加载器子系统处理的。它负责加载、链接,并且在运行时首次引用类的时候初始化类,而不是在编译期间。

1.1、加载

这个组件负责加载类。BootStrap类加载器、Extension类加载器和Application类加载器是实现这个功能的三大类加载器。

  1. BootStrap类加载器 —— 负责从classpath加载类,如果没有类存在,将只加载rt.jar。这个加载器的优先级最高。
  2. Extension类加载器 —— 负责加载扩展文件夹(jre\lib)中的类。
  3. Application类加载器 —— 负责加载应用级classpath和环境变量指向的路径下的类。

上述类加载器在加载类文件时遵循委托层次结构算法

1.2、链接

  1. 校验 —— 字节码验证器将校验生成的字节码是否正确,如果校验失败,我们将获得校验错误信息
  2. 准备 —— 对于所有的静态变量,内存将被申请并分配默认值。
  3. 解析 —— 所有标记的内存引用方法区域被替换成的原始引用

1.3、初始化

这是类加载的最后阶段,所有的静态变量都将被分配原值,静态代码块将被执行。

2、运行时数据区

运行时数据区被划分为五个主要部分:

  1. 方法区 —— 所有类级数据都将存储在这里,包括静态变量。每一个JVM只有一个方法区,并且它是一个共享资源。
  2. 堆区 —— 所有对象及其对应的实例变量数组等存储在此,每个JVM同样只有一个堆区。由于方法区堆区是多线程内存共享,因此存储的数据是非线程安全的。
  3. 栈区 —— 每个线程都会创建一个单独的运行时栈。在每一次方法调用,都会在栈内存中创建一个栈帧(Stack Frame)。所有局部变量将在栈内存中创建。栈区是线程安全的,因为它不是一个共享资源。栈帧可以被划分为三个实体:

    1. 局部变量数组 —— 与方法中有多少局部变量有关,相应的值将存储在此处。
    2. 操作数栈 —— 如果任何的中间操作需要被执行,操作数栈将作为运行时工作区来执行操作。
    3. 帧数据 —— 与方法相对应的所有符号存储在此。在任何异常情况下,catch块的信息被保留在帧数据中。
  4. PC寄存器 —— 每一个线程都有单独的PC寄存器,一旦执行指令,PC寄存器将被下一条指令更新,保存当前执行指令的地址。

  5. 本地方法栈 —— 本地方法栈保存本地方法信息,每一个线程都会创建一个单独的本地方栈。

3、执行引擎

分配到运行时数据区的字节码将被执行引擎执行。执行引擎读取字节码并逐一执行。

  1. 解释器 —— 解释器能更加快速地解释字节码,但是执行缓慢。解释器的缺点是当多次调用一个方法时,每次都要重新解释。
  2. JIT编译器 —— JIT编译器弥补了解释器的不足。执行引擎使用解释器来转换字节码,当它发现重复的代码时,它将使用JIT编译器来编译整个字节码并转换为本地代码。本地代码将直接被重复的方法所调用,从而提高系统性能。
  3. 中间代码生成器 —— 生成中间代码。
  4. 代码优化器 —— 负责优化上述生成的中间代码。
  5. 目标代码生成器 —— 负责生成机器码或者本地代码。
  6. 分析器 —— 一个特殊的组件,负责查找热点代码,比如一个方法是否被调用多次。
  7. 垃圾回收器 —— 回收并删除未引用的对象。可以通过调用System.gc()来触发垃圾回收,但不能保证它执行。JVM的垃圾回收是回收被创建的对象。

Java本地接口(JNI)JNI本地方法库交互,并为执行引擎提供本地方法库

本地方法库(Native Method Libraries):它是执行引擎所需的本地库集合。