Java源代码是怎么被机器识别并执行的呢?答案是Java虚拟机。

一、字节码

0和1是计算机仅能识别的信号,经过0和1的不同组合产生了数字之上的操作。另外通过不同的组合亦产生了各种字符。同样可以通过不同的组合产生不同的机器指令。

机器码是离CPU指令集最近的编码,是CPU可以直接解读的指令,因此机器码肯定是与底层硬件系统耦合的。

在代码执行的过程中,JVM将字节码解释执行,屏蔽对底层操作系统的依赖;JVM也可以将字节码编译执行,如果是热点代码,会通过JIT动态地编译为机器码,提高执行效率。

字节码主要指令如下:

(1)加载和存储指令

在某个栈帧中,通过指令操作数据在虚拟机栈的局部变量表与操作栈之间来回传输,常见指令如下:

  • 将局部变量加载到操作栈中。如ILOAD(将int类型的局部变量压入栈和ALOAD(将对象引用的局部变量压入栈)等。
  • 从操作栈顶存储到局部变量表。如ISTORE、ASTORE等。
  • 将常量加载到操作栈顶,这是极为高频使用的指令。如 ICONST、BIPUSH、SIPUSH、LDC等。

(2)运算指令

对两个操作栈帧上的值进行运算,并把结果写入操作栈顶,如IADD、IMUL等。

(3) 类型转换指令

显示转换两种不同的数值类型。如I2L、D2F等。

(4)对象创建与访问指令

根据类进行对象的创建、初始化、方法调用相关指令,常见指令如下:

  • 创建对象指令
  • 访问属性指令
  • 检查实例类型指令

(5)操作栈管理指令

JVM提供了直接控制操作栈的指令,常见指令如下:

  • 出栈操作。如POP即一个元素,POP2即两个元素。
  • 复制栈顶元素并压入栈。如DUP。

(6)方法调用与返回指令

  • INVOKEVIRTUAL 指令: 调用对象的实例方法
  • INVOKESPECIAL 指令: 调用实例初始化方法、私有方法、父类方法等
  • INVOKESTATIC 指令: 调用类静态方法
  • RETURN 指令:返回VOID类型

(7)同步指令


JVM 使用方法结构中的ACC SYN HRONIZ 标志同步方法 指令集中有MONITORENTER MONJTOREXIT 支持 synchroni ze 语义。


我们编写好的.java文件是源代码文件,并不能交给机器直接执行,需要将其编译称为字节码甚至是机器码文件。静态编译器将源码转字节码流程:

Java虚拟机--JVM_类加载

      词法解析是通过空格分隔出单词,操作符,控制符等信息,将其形成token信息流,传递给语法解析器;在语法解析时,把词法解析得到的token信息流按照JAVA语法规则组成以可语法树,在语义分析阶段,需要检查关键字的使用是否合理、类型是否匹配、作用域是否正确等;当语义分析完成之后,即可生成字节码。

字节码必须通过类加载过程加载到JVM环境后,才可以运行。字节码必须通过类加载过程加载到JVM 环境后,才可以执行。执行有三种模式第一,解释执行,第二, JIT 编译执行第三, JIT 编译与解释混合执行(主流 JVM默认执行模式)。混合执行模式的优势在于解释器在启动时先解释执行,省去编译时间。随着时间推进 JVM通过热点代码统计分析 识另 高频的方法调用、循环体、公共模块等,基于强大的JlT 动态编译技术,将热点代码转换成机器码,直接交给 PU执行。 JIT 作用是将Java 字节码动态地编译成可以直接发送给处理器指令执行的机器码。简要流程如图 所示。

Java虚拟机--JVM_字节码_02

二、类加载过程

任何程序都需要加载到内存才能与CPU进行交流。字节码.class文件同样需要加载到内存中,才可以实例化类。ClassLoader的使命就是提前加载.classl类文件到内存中。在加载类时,使用的是“Parent Delegation Model” 译为双亲委派模型。

Java的类加载器是一个运行时核心基础设施模块,主要是在启动之初进行类的Load、Link、Init,即加载、链接、初始化。

  • 第一步,Load 阶段读取类文件产生二进制流,并转化为特定的数据结构,初步校验cafe babe魔法数、常量池、文件长度、是否有父类等,然后创建对应类的java.lang.Class实例。
  • 第二步,Link 阶段包括验证、准备、解析三个步骤。验证是更详细的校验,比如final是否合规、类型是否正确、静态变量是否合理等;准备阶段是为静态变量分配内存,并设定默认值,解析类和方法确保类与类之间的相互引用正确性,完成内存结构布局。
  • 第三步,Init 阶段执行类构造器<clinit>方法,如果赋值运算是通过其他类的静态方法来完成的,那么会马上解析另一个类,在虚拟机栈中执行完毕后通过返回值进行赋值。

Java虚拟机--JVM_字节码_03

                                                                                类加载过程图

 

       类加载是一个将.class字节码文件实例化成Class对象并进行相关初始化的过程。在这个过程中,JVM会初始化继承树上还没有被初始化的所有父类,并且会执行这个链路上所有未执行过的静态代码块、静态变量赋值语句等。某些类在使用时,也可以按需由类加载器进行加载。