什么是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和开发工具

学习JVM有什么用?

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

常见的JVM

JVM 在 Java 中是如何工作的

  • 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):对于每个线程,都会创建一个单独的运行时堆栈。对于每个方法调用,都会在堆栈内存中创建一个条目,称为栈帧。所有局部变量都将在堆栈内存中创建。堆栈区域是线程安全的,因为它不是共享资源。Stack Frame分为三个子实体如下
    1. 局部变量数组:与方法有关,涉及多少个局部变量,相应的值将存储在这里。
    2. 操作数栈:如果需要执行任何中间操作,操作数栈充当运行时工作空间来执行操作。
    3. 帧数据:所有与方法对应的符号都存储在这里。在任何异常的情况下,catch块信息将在帧数据中维护。
  4. 程序计数器(PC Registers):每个线程都有独立的程序计数器,用于保存当前执行指令的地址 ,一旦指令执行,程序计数器将被下一条指令更新
  5. 本地方法栈(Native Method stacks):保存本地方法信息。对于每个线程,将创建单独的本地方法堆栈。

执行引擎

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