什么是JVM?

  • 定义
    • Java Virtual Machine— Java程序的运行环境(Java二进制字节码的运行环境)
  • 好处
    1. 一次编译,到处运行
    2. 自动内存管理,垃圾回收功能
    3. 数组下表越界检查
    4. 多态
  • 比较JVM、JRE、JDK
    • JVM(Java Virtual Machine),Java虚拟机
    • JRE(Java Runtime Environment),Java运行环境,包含了JVM和Java的核心类库(Java API)
    • JDK(Java Development Kit)称为Java开发工具,包含了JRE和开发工具
      img

学习JVM有什么用?

  • 面试
  • 理解底层实现原理
  • 中高级程序员的必备技能

常见的JVM

img

JVM 在 Java 中是如何工作的

img

  • JVM主要分为三个子系统
    1. 类加载器(ClassLoader)
    2. JVM运行时数据区(内存结构)
    3. 执行引擎

类加载器系统

  • Java 的动态类加载功能由类加载器子系统处理。它在运行时第一次引用一个类时加载、链接和初始化该类,而不是在编译时。
  • 它执行三个主要功能
    • 加载
    • 链接
    • 初始化

加载

  • 该组件将加载类。
  • BootStrap ClassLoader、Extension ClassLoader、Application ClassLoader 是三个有助于实现它的类加载器。
    • BootStrap ClassLoader 启动类加载器是所有其他类加载器的parent(rt.jar包下的类)
    • Extension ClassLoader 扩展类加载器加载核心 Java 类的扩展类(ext/*.jar包下的类)
    • Application ClassLoader 应用类加载器加载在classpath中的我们自己写的文件

连接

  • 这部分要做三件事
    1. 验证(Verify)
      • 验证被加载的类的准确性,保证安全,不被恶意修改
      • 有四种验证方式,文件格式验证,元数据验证,字节码验证,符号引用验证
    2. 准备(Prepare)
      • 为类变量分配内存并且设置该类变量的默认初始值,也就是零值,即在准备阶段,类的变量都会是默认值,只有到了初始化阶段(initization),才会赋值
      • 如果用final修饰的static变量,那么在这个阶段,就会显示初始化,因为final在编译的时候就分配了空间和值
    3. 解析(Resolve)
      • 将常量池内的符号引用转换为直接引用的过程
      • 解析伴随着初始化执行完之后再执行

初始化

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

JVM内存结构

  1. 方法区(Method Area):所有类级别的数据都将存储在这里,包括 静态变量。方法区是每个 JVM 一个,它是一种共享资源。

  2. 堆(Heap Area):所有的Objects及其对应的实例变量 和数组都将存储在这里。堆区也是每个 JVM 一个,因为方法区和堆区为多个线程共享内存,存储的数据不是线程安全的。

  3. 虚拟机栈(Stack Area)
    
    1
    2
    3

    :对于每个线程,都会创建一个单独的运行时堆栈。对于每个方法调用,都会在堆栈内存中创建一个条目,称为

    栈帧
    1
    2
    3

    。所有局部变量都将在堆栈内存中创建。堆栈区域是线程安全的,因为它不是共享资源。

    Stack Frame
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    分为三个子实体如下

    1. `局部变量数组`:与方法有关,涉及多少个局部变量,相应的值将存储在这里。
    2. `操作数栈`:如果需要执行任何中间操作,操作数栈充当运行时工作空间来执行操作。
    3. `帧数据`:所有与方法对应的符号都存储在这里。在任何异常的情况下,catch块信息将在帧数据中维护。

    4. `程序计数器(PC Registers)`:每个线程都有独立的程序计数器,用于保存当前执行指令的地址 ,一旦指令执行,程序计数器将被下一条指令更新

    5. `本地方法栈(Native Method stacks)`:保存本地方法信息。对于每个线程,将创建单独的本地方法堆栈。

    ## 执行引擎

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

    1. `解释器`:读取字节码,解释并逐一执行。解释器解释字节码的速度更快,但执行速度较慢。解释器的缺点是当一个方法调用多次时,每次都需要解释。

    2. ```
    JIT 编译器
    :JIT 编译器抵消了解释器的缺点(一个方法调用多次,每次都需要解释),执行引擎将使用解释器的帮助进行转换,但当它发现重复代码时,它使用 JIT 编译器编译整个字节码并将其更改为本机代码。此本机代码将直接用于提高系统性能的重复方法调用。 1. 中间代码生成器:生成中间代码 2. 代码优化器:负责优化上面生成的中间代码 3. 目标代码生成器:负责生成机器代码/本机代码 4. Profiler:Profiler是一个特殊的组件,它负责发现热点(即)用于识别方法是否被多次调用。
  4. 垃圾收集器:垃圾收集器是执行引擎的一部分,它收集/删除未引用的对象。可以通过调用System.gc()来触发垃圾收集,但不能保证执行。JVM 的垃圾收集器只收集那些由new关键字创建的对象。因此,如果您创建了任何没有使用new的对象,您可以使用finalize方法来执行清理。

  • Java Native Interface(JNI):JNI将与本机方法库交互,并提供执行引擎所需的本机库。

  • 本地方法库:这是执行引擎所需的本地库的集合。