目录

一、什么是JVM(Java虚拟机)?

二、JVM的功能

三、JVM的功能-即时编译

四、常见的JVM

五、JVM的组成

五、JVM的工作流程

参考资料


一、什么是JVM(Java虚拟机)?

在Java的世界里,Java虚拟机(JVM)扮演着至关重要的角色。它不仅是Java程序运行的环境,更是实现“一次编写,到处运行”的关键。本文将深入探讨JVM的核心组成部分,从类加载到执行引擎,解开JVM神秘的面纱。

JVM本质上是一个运行在计算机上的程序,他的职责是运行Java字节码文件

JVM,即Java虚拟机,是一个用于执行Java字节码的虚拟计算机。它是在硬件或操作系统上构建的一个软件层,使Java字节码可以在不同的平台上运行。即时编译(Just-In-Time compilation)是JVM的一个关键功能,它允许JVM在运行时将字节码编译成本地代码,以提高程序的性能。

即时编译的主要功能如下:

  1. 预编译(Compile-Ahead-Of-Time):JVM首先将Java源代码编译成字节码,然后这些字节码在运行时被即时编译成本地代码。这种预编译的方式使得程序在第一次运行时不需要进行编译,从而提高了程序的启动速度。
  2. 热点代码优化:JVM通过热点代码优化技术来提高程序的运行效率。热点代码是指被频繁执行的代码。JVM在运行时收集这些热点代码的执行信息,并将它们编译成更高效的本地代码。这种优化可以显著提高程序的性能,特别是对于那些频繁运行的代码。
  3. 动态编译:即时编译还支持动态编译。这意味着JVM可以根据程序在运行时的行为动态地调整编译策略。例如,如果某个方法没有被频繁调用,那么JVM可以暂时不将其编译成本地代码,以节省资源。相反,如果某个方法被频繁调用,JVM可以将其优先编译成本地代码,以提高程序的运行效率。
  4. 内存管理和垃圾回收:JVM还提供了内存管理和垃圾回收的功能。这些功能可以帮助程序员更好地管理内存资源,并提高程序的可靠性。

总之,即时编译是JVM的一个重要功能,它可以帮助程序员提高程序的性能和可靠性。通过将Java字节码编译成本地代码,JVM可以减少解释字节码所需的时间,从而提高程序的执行速度。同时,即时编译还可以根据程序在运行时的行为动态地调整编译策略,以进一步提高程序的性能。

将字节码文件转换成计算机可以看懂的机器码文件。这就是Java虚拟机的主要功能。

二、JVM的功能

三、JVM的功能-即时编译

JVM可以将热点的代码字节指令,保存到内存中,等到再次执行时可以直接调用。

四、常见的JVM

常见的JVM包括HotSpot、JRockit、J9等。

HotSpot是较新的Java虚拟机技术,用来代替JIT(just-in-time compilation,及时编译)技术,可以大大提高Java运行的性能。HotSpot将常用的部分代码编译为本地(原生,native)代码,这样显著提高了性能。它从运行应用中采样数据,从而可以优化代码,进而得到良好性能。HotSpot引擎可以集中精力来对HotSpot代码进行深度优化,从而使这部分代码的执行更加迅捷。但它的启动时间较长。

JRockit是BEA公司开发的,可以直接运行在自家Hypervisor系统上的JRockit VM的虚拟化版本,JRockit VM不需要操作系统的支持,或者说它自己本身实现了一个专用操作系统的必要功能,如文件系统、网络支持等。

IBM J9是IBM开发的Java虚拟机,它也支持即时编译技术。

我们开发时,基本都会优先选择使用HotSpot。

五、JVM的组成

JVM主要组成有四个子系统组成:类加载系统运行时数据区域执行引擎本地方法接口

  1. 类加载系统(Class Loading System):

    • 加载(Loading): 加载是指查找字节码文件,并创建一个Class对象的过程。字节码文件通常由Java编译器从Java源代码生成。
    • 验证(Verification): 确保字节码文件符合Java语言规范,并且不包含不安全或非法的代码。
    • 准备(Preparation): 为类的静态变量分配内存并设置默认初始值。
    • 解析(Resolution): 将常量池中的符号引用替换为直接引用,使得各个类之间能够正确地引用。
  2. 执行引擎(Execution Engine):

    • 解释器(Interpreter): 将字节码文件逐行解释为机器码并执行。
    • 即时编译器(Just-In-Time Compiler,JIT): 将整个字节码文件编译为机器码,提高执行速度。
    • 栈操作(Stack Operations): 使用操作栈进行方法调用、参数传递等。
  3. 本地方法接口(Native Interface):

    • 允许Java应用程序调用本地方法(通常使用C或C++编写的代码)。Java的本地方法接口允许Java代码与本地库进行交互,实现了Java与其他语言的衔接。JVM通过本地库接口与操作系统提供的库进行交互,保证了Java程序的可移植性。
  4. 运行时数据区域(Runtime Data Area):

    • 方法区(Method Area): 存储类的结构信息,如类的字段、方法信息。
    • 堆(Heap): 存储对象实例,包括程序运行时创建的对象。
    • 栈(Stack): 存储局部变量、方法调用和返回地址。
    • 程序计数器(Program Counter): 记录当前线程执行的字节码行号。
    • 本地方法栈(Native Method Stack): 执行本地方法时使用的栈。

Java程序能够在不同平台上实现“一次编写,到处运行”的特性。类加载系统负责加载和验证Java类,执行引擎负责执行Java代码,本地方法接口提供了与底层系统的交互能力,而运行时数据区域存储程序执行时的数据。JVM通过本地库接口与操作系统提供的库进行交互,保证了Java程序的可移植性。

以上图来源于黑马课件

此图来源于《深入理解Java虚拟机》

五、JVM的工作流程

JVM的工作流程通常包括以下几个步骤:

  1. 加载(Loading)
    加载阶段是JVM启动的第一个阶段,它负责从系统中加载Java类和接口的定义信息。加载阶段的主要任务是找到并加载Java类和接口的定义信息,并将其存储在内存中。这些定义信息包括类的成员变量、成员方法、构造函数等。在加载阶段,JVM还会对类的定义信息进行验证,以确保其符合Java语言的规范。
  2. 链接(Linking)
    链接阶段是加载阶段的后续阶段,它负责验证类的定义信息、为类的成员变量分配内存并设置默认值,以及解析类的符号引用。在链接阶段,JVM会对类进行一系列的验证,以确保其符合Java语言的规范。如果验证不通过,则会抛出异常。此外,链接阶段还会为类的成员变量分配内存并设置默认值,以及解析类的符号引用。符号引用是指用符号来引用类、方法、变量等的一种方式。
  3. 初始化(Initialization)
    初始化阶段是链接阶段的后续阶段,它负责执行类的初始化代码。初始化阶段的主要任务是执行类的初始化代码,包括静态初始化块和静态初始化方法。在初始化阶段,JVM会执行类的静态代码块和静态变量的初始化代码。如果存在多个静态变量或静态代码块,则会按照它们在类中的顺序依次执行。
  4. 执行(Execution)
    执行阶段是JVM的核心阶段,它负责执行Java程序的字节码指令。执行阶段的主要任务是执行Java程序的字节码指令,包括对成员变量的读写操作、方法的调用等。在执行阶段,JVM会根据程序的指令逐条执行字节码指令,从而实现Java程序的运行。
  5. 卸载(Unloading)
    卸载阶段是JVM的最后一个阶段,它负责卸载不再被使用的Java类和接口的定义信息。卸载阶段的主要任务是回收被卸载的类占用的内存空间,以便重新被使用。在卸载阶段,JVM会回收被卸载的类占用的内存空间,以便重新被使用。

以上就是JVM的基本工作流程,不同的JVM实现可能会有一些差异,比如内存分配策略、垃圾收集器类型等。

深入了解Java虚拟机,我们不仅能够更好地理解Java程序的运行机制,还能够优化程序性能、解决内存泄漏等问题。JVM的神秘面纱下,是一个复杂而高效的执行环境,为Java的成功贡献着重要的力量。让我们在编写Java程序的同时,更加深入地认识JVM,为程序的优化和调优提供更多的可能性。

参考资料

  • The Java® Virtual Machine Specification
  • 深入理解Java虚拟机(第三版)