快速理解 JVM 原理 - 【基础概念篇】

快速理解 JVM 原理 - 【基础概念篇】

Java虚拟机 是什么?

Java 虚拟机 本质就是一台”虚拟的“计算机 ,大家通俗的理解是一款 “软件”安装在电脑上

虚拟机通常分为两类:

  • 系统虚拟机【可运行完整操 作系统的软件平台】
  • 程序虚拟机 【为执行单个计算机程 序而设计】

无论是 哪种类型都被限制于虚拟机提供的资源中在这里插入图片描述

常见的编程语言类型

虚拟机和语言存在着 密不可分的关系,因此 Java 虚拟机也是基于 **虚拟机类似的静态编译性语言**。

常见的编程语言有三类

  1. 机器语言
    解释:直接向宿主机执行二进制指令0101,无需经过翻译,每一操作码在计算机内部都有相应的电路来完成它。
  2. 汇编语言
    任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言。可以使用助记符序列而不是数字操作代码,最计算机进行操作。
  3. 高级语言
    方便大家理解,进而快速设计和实现程序代码,代码完成后通过编译或解释 转换成汇编或者机器对应执行码在去机器中执行。
    在这里插入图片描述

Java 跨平台性体现

C语言 不同系统编译的文件形态是不同的
在这里插入图片描述
Java 语言 通过虚拟机统一处理编译成字节数据
在这里插入图片描述


    Java虚拟机组成

    Java虚拟机组成 主要由4部分组成

    • ClassLoader(类加载器)
    • Runtime Data Area(运行时数据区,内存分区)
    • Execution Engine(执行引擎)
    • Native Interface(本地库接口)

    核心流程

    在这里插入图片描述

    ClassLoader(类加载器)

    ClassLoader 负责加载字节码文件即 class 文件,class 文件在文件开头有特定的文件标示,并且 ClassLoader 只负责class 文件的加载。

    类的生命周期和加载过程

    一个类在JVM里的生命周期有7个阶段。
    分别是加载(Loading)、校验 (Verification)、准备(Preparation)、解析(Resolution)、初始化 (Initialization)、使用(Using)、卸载(Unloading)。 其中前五个部分(加载,验证,准备,解析,初始化)统称为类加载.
    在这里插入图片描述
    加载(Loading)

    就是 找到文件系统中/jar包中/或存在于任何地方的“ class文件 ”。 如果找不到二进制表示 形式,则会抛出 NoClassDefFound 错误
    装载阶段并不会检查 classfile 的语法和格式。

    校验(Loading)

    链接过程的第一个阶段是 校验 ,确保class文件里的字节流信息符合当前虚拟机的要 求,不会危害虚拟机的安全。

    准备(Preparation)

    进入准备阶段,这个阶段将会创建静态字段, 并将其初始化为标准默认值(比如 null 或者 0值 ),并分配方法表,即在方法区中分配这些变量所使用的内存空间。
    解析(Resolution)
    简单的来说就是我们编写的代码中,当一个变量引用某个对象的时候,这个引用在 .class 文件中是以符号引用来存储的(相当于做了一个索引记录)。 在解析阶段就需要将其解析并链接为直接引用(相当于指向实际对象)。如果有了直 接引用,那引用的目标必定在堆中存在。 加载一个class时, 需要加载所有的super类和super接口。
    初始化(Resolution)

    JVM规范明确规定, 必须在类的首次“主动使用”时才能执行类初始化。
    初始化的过程包括执行:

    • 类构造器方法 static
    • 静态变量赋值语句
    • static静态代码块
      如果是是一个子类进行初始化会先对其父类进行初始化,保证其父类在子类之前进行初 始化。所以其实在java中初始化一个类,那么必然先初始化过 java.lang.Object 类,因为所有的java类都继承自java.lang.Object。

    Execution Engine(执行引擎)

    执行引擎,也叫 Interpreter。Class 文件被加载后,会把指令和数据信息放入内存中,Execution Engine 则负责把这些命令解释给操作系统,即将 JVM 指令集翻译为操作系统指令集

    Native Interface(本地接口)

    负责调用本地接口的。核心作用是调用不同语言的接口给 JAVA 用,他会在 Native Method Stack 中记录对应的本地方法,然后调用该方法时就通过 Execution Engine 加载对应的本地 lib

    Runtime Data Area(运行时数据区,内存分区)

    在这里插入图片描述

    运行时描述摘抄参考文献 《深入理解JVM 虚拟机-第三版》 -周志明-尊重原创!!
    程序计数器
    程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的 字节码的行号指示器。在Java虚拟机的概念模型里[1],字节码解释器工作时就是通过改变这个计数器 的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处 理、线程恢复等基础功能都需要依赖这个计数器来完成。

    由于 Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的
    一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因 此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程 之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

    Java虚拟机栈
    与程序计数器一样,**Java虚拟机栈(Java Virtual Machine Stack)**也是线程私有的,它的生命周期 与线程相同。虚拟机栈描述的是Java方法执行的线程内存模型: 每个方法被执行的时候,Java虚拟机都 会同步创建一个栈帧[1](Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
    由于 Java虚拟机的多线程是通过线程轮流切换、分配处理器执行时间的方式来实现的。

    本地方法栈

    本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机 栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native) 方法服务。

    Java堆
    对于Java应用程序来说,Java堆(Java Heap)是虚拟机所管理的内存中最大的一块。Java堆是被所 有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,Java 世界里“几乎”所有的对象实例都在这里分配内存。

    在这里插入图片描述

    方法区
    方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载 的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据

    **运行时常量池(Runtime Constant Pool)**是方法区的一部分。Class文件中除了有类的版本、字 段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生 成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。


      参考资料
      周志明-深入理解JVM数据

      猜你喜欢

      转载自blog.csdn.net/jjc120074203/article/details/128921376