JVM 架构—JVM 内部是如何工作的?

开发 后端
Java 应用程序称为 WORA(Write Once Run Anywhere)。这意味着程序员可以在一个系统上开发 Java 代码,并且可以期望它无需任何调整就可以在任何其他支持 Java 的系统上运行。由于 JVM,这一切都是可能的。

什么是虚拟机?

JVM(Java Virtual Machine):它是一个引擎,为Java应用程序提供运行时环境,并负责转换通过编译(.java文件)生成的字节码(.class文件)。JVM 是 Java 运行时环境 (JRE) 的一部分。

Java 应用程序称为 WORA(Write Once Run Anywhere)。这意味着程序员可以在一个系统上开发 Java 代码,并且可以期望它无需任何调整就可以在任何其他支持 Java 的系统上运行。由于 JVM,这一切都是可能的。

JVM 架构:

JVM分为三个主要的子系统:

  • 类加载器
  • 运行时数据区(内存区)
  • 执行引擎

1、类加载器:

ClassLoader 是 Java 运行时环境 (JRE) 的一部分,可将 Java 类文件从文件系统、网络或任何其他来源动态加载到 Java 虚拟机中。它分为三个主要阶段:

  • 加载中
  • 链接
  • 初始化

(1)加载:

是负责从各种资源(例如文件系统、jar 文件、网络套接字)将字节代码(.class 文件)加载到内存中的部分。

Load阶段涉及三种不同类型的ClassLoader:

  • Bootstrap Class Loader: 它加载 JDK 内部类。它加载rt.jar和其他核心类,例如 java.lang.* 包类。
  • 扩展类加载器: 它从 JDK 扩展目录加载类,通常是$JAVA_HOME/lib/ext目录。
  • 应用程序类加载器: 它从当前类路径加载类。我们可以在使用 -cp 或 -classpath 命令行选项调用程序时设置类路径。

ClassLoader 在 Java 中是如何工作的

当JVM 请求一个类时,它通过传递类的完全分类名称来调用java.lang.ClassLoader 类的loadClass() 方法。loadClass() 方法调用 findLoadedClass() 方法来检查该类是否已经加载。需要避免多次加载类。

如果该类未加载,它将请求委托给父 ClassLoader 以加载该类。如果 ClassLoader 没有找到类,它会调用 findClass() 方法在文件系统中查找类。下图显示了 ClassLoader 如何使用委托在 Java 中加载类。

假设我们有一个特定于应用程序的类 Student.class。加载此类文件的请求将传输到 Application ClassLoader。它委托给它的父扩展类加载器。此外,它委托给 Bootstrap ClassLoader。Bootstrap 在 rt.jar 中搜索该类,因为该类不存在。现在请求传输到 Extension ClassLoader,它搜索目录 jre/lib/ext 并尝试在其中找到此类。如果在此处找到该类,Extension ClassLoader 将加载该类。Application ClassLoader 从不加载该类。当扩展 ClassLoader 不加载它时,Application ClaasLoader 从 Java 中的 CLASSPATH 加载它。

可见性原则是说子ClassLoader可以看到父ClassLoader加载的类,反之则不然。这意味着如果 Application ClassLoader 加载 Student.class,在这种情况下,尝试使用 Extension ClassLoader 显式加载 Student.class 会抛出
java.lang.ClassNotFoundException。

(2)链接:

主要分为三个阶段:

  • 验证:它确保.class文件(字节码)的正确性 ,即它检查此文件是否正确格式化并由有效的编译器生成,以及是否与 JVM 类规范兼容。如果验证失败,我们会得到运行时异常 java.lang.VerifyError。此活动由组件ByteCodeVerifier完成。完成此活动后,类文件就可以编译了。
  • 准备:准备包括为类或接口创建静态字段并将这些字段初始化为其默认值。这不需要执行任何 Java 虚拟机代码;静态字段的显式初始化程序作为初始化的一部分而不是准备执行。
  • Resolution:是从运行时常量池中的符号引用动态确定具体值的过程。

JVM 指令 anewarray、checkcast、getfield、getstatic、instanceof、invokedynamic、invokeinterface、invokespecial、invokestatic、invokevirtual、ldc、ldc_w、multiawarray、new、putfield 和 putstatic 对运行时常量池进行符号引用 。执行这些指令中的任何一条都需要解析其符号引用。

(3)初始化:

这是类加载的最后阶段,这里所有的静态变量都将被赋予原始值,并执行静态块。

2、运行时数据区:

(1)方法区(Method Area):

Java 虚拟机有一个 在所有 Java 虚拟机线程之间共享的方法区。方法区类似于常规语言的编译代码的存储区,或者类似于操作系统进程中的“文本”段。它存储每个类的结构,例如运行时常量池、字段和方法数据,以及方法和构造函数的代码,包括类和实例初始化以及接口初始化中使用的特殊方法。

  • 如果方法区中的内存无法满足分配请求,Java 虚拟机将抛出 OutOfMemoryError。

(2)堆(Heap):

Java 虚拟机有一个 在所有 Java 虚拟机线程之间共享的堆。堆是运行时数据区域,从中分配所有类实例和数组的内存。

堆是在虚拟机启动时创建的。对象的堆存储由自动存储管理系统(称为 垃圾收集器)回收;对象永远不会显式释放。Java 虚拟机没有假定特定类型的自动存储管理系统,可以根据实现者的系统要求选择存储管理技术。堆可以是固定大小的,也可以根据计算的需要进行扩展,如果不需要更大的堆,则可以收缩。堆的内存不需要是连续的。

Java 虚拟机实现可以让程序员或用户控制堆的初始大小,如果堆可以动态扩展或收缩,还可以控制最大和最小堆大小。

以下异常情况与堆相关联:

  • 如果计算需要的堆多于自动存储管理系统所能提供的堆,则 Java 虚拟机将抛出 OutOfMemoryError。

(3)堆栈(Stack):

每个 Java 虚拟机线程都有一个私有的 Java 虚拟机堆栈,与线程同时创建。Java 虚拟机堆栈存储帧。Java 虚拟机堆栈类似于 C 等常规语言的堆栈:它保存局部变量和部分结果,并在方法调用和返回中发挥作用。因为 Java 虚拟机堆栈从不直接操作,除了压入和弹出帧外,帧可能是堆分配的。Java 虚拟机堆栈的内存不需要是连续的。

在The Java® Virtual Machine Specification第一版中 ,Java 虚拟机堆栈被称为 Java 堆栈。

此规范允许 Java 虚拟机堆栈具有固定大小或根据计算需要动态扩展和收缩。如果 Java 虚拟机堆栈的大小是固定的,则每个 Java 虚拟机堆栈的大小可以在创建该堆栈时独立选择。

Java 虚拟机实现可以为程序员或用户提供对 Java 虚拟机堆栈初始大小的控制,以及在动态扩展或收缩 Java 虚拟机堆栈的情况下,对最大和最小大小的控制。

以下异常情况与 Java 虚拟机堆栈相关:

  • 如果线程中的计算需要比允许的更大的 Java 虚拟机堆栈,Java 虚拟机将抛出 StackOverflowError。
  • 如果 Java 虚拟机堆栈可以动态扩展,并且尝试扩展但没有足够的内存可用于实现扩展,或者如果没有足够的内存可用于为新线程创建初始 Java 虚拟机堆栈,则 Java 虚拟机机器抛出 OutOfMemoryError。

(4)PC注册(PC Register):

它存储当前执行的指令的地址。

(5)原生方法栈(Native Method Stack):

Native Method Stack 保存本地方法信息。对于每个线程,都会创建一个单独的本机方法堆栈。

3、执行引擎:

执行引擎通过执行每个类中存在的代码来处理此问题。但是,在执行程序之前,需要将字节码转换为机器语言指令。JVM 可以使用解释器或 JIT 编译器作为执行引擎。

它可以分为三个部分:

解释器:解释器逐行读取并执行字节码指令。由于逐行执行,解释器相对较慢。

解释器的另一个缺点是当一个方法被多次调用时,每次都需要重新解释。

即时编译器(JIT) :用于提高解释器的效率。它编译整个字节码并将其更改为本地代码,因此每当解释器看到重复的方法调用时,JIT 会为该部分提供直接的本地代码,因此不需要重新解释,从而提高了效率。

垃圾收集器:它销毁未引用的对象。有关垃圾收集器的更多信息,请参阅 Java Garbage Collection Basics。

Java 本机接口 (JNI):

它是一个与本地方法库交互并提供执行所需的本地库(C、C++)的接口。它使 JVM 能够调用 C/C++ 库,并被可能特定于硬件的 C/C++ 库调用。

本机方法库:

它是执行引擎所需的本机库(C、C++)的集合。

责任编辑:姜华 来源: 今日头条
相关推荐

2021-09-08 17:16:00

JVM反射 Java

2024-07-30 14:01:51

Java字节码JVM​

2022-06-22 09:54:45

JVM垃圾回收Java

2021-06-03 08:32:18

JVM调优虚拟机

2021-07-06 13:32:55

JVM

2021-07-01 19:30:23

JVM内部锁线程

2012-08-27 09:10:05

JVMJava

2023-10-08 15:23:12

2021-06-30 14:11:01

JVM对象池Java

2010-09-16 14:42:44

JVM

2010-09-26 08:50:11

JVM工作原理

2009-07-09 14:01:22

JVM工作原理

2021-01-19 10:35:49

JVM场景函数

2010-09-17 13:10:29

JVMJava虚拟机

2010-09-17 13:15:55

JVMJava虚拟机

2024-11-25 08:31:50

JVMJava内存管理

2010-09-26 16:14:22

JVM实现机制JVM

2020-12-30 09:18:46

JVM内部信息

2012-01-11 13:04:40

JavaJVM

2021-06-09 07:56:51

JvmJVM面试题Java
点赞
收藏

51CTO技术栈公众号