在之前的JVM专栏中具体说明了各个JVM内存区域的信息、功能作用等。以及讲到了jdk不同版本针对GC操作使用垃圾收集器的区别等。
相信大家对一个Java程序的执行过程还是有点好奇的。
本篇博客就从Java程序到计算机CPU执行这个过程做一个介绍和说明。
假设需要执行下列案例:
public class Math { public void test(){ int a = 0; int b = 5; System.out.println(a+b); } public static void main(String[] args) { Math td = new Math(); td.test(); } }
一个.java
程序在执行之前,需要将其转化为.class
字节码文件,加载至jvm
中,然后让计算机去执行。其加载过程图如下所示:
其中,JVM将.class
文件信息加载至JVM虚拟机中的过程,使用的是JVM的类装载子系统
,其执行操作如下所示:
当xx.class
类中的类执行了加载操作后,会将其中的类元信息
加载至JVM的方法区
中,如下所示:
【疑问:】哪些是类元信息?
使用命令
javap -v Math.class
执行后,下列的Constant pool
即为类元信息,
方法区
主要保存常量 final(包含常量池)
、静态变量 static
、类元信息(类的常量池)
。
当执行main
方法时,会在栈中开辟一块区间,存放相应的信息。
main是程序的入口,也是一个线程。
执行实例化new Math()
操作,会在堆中创建实例化对象地址信息。并将栈中的td 局部变量
,针对堆中的Math实例对象
地址进行引用。
当采取td.test()
调用实例化对象中的指定方法时,此时则需要借用字节码执行引擎
实现相关操作,如下所示:
首先,会在栈
中分配一块内存区域,创建main
线程。
其次,引用test()
,则继续在对应栈内存中压入test()
。
在执行test()
中的程序逻辑时,会依次对其中的指令进行操作。
这个指令是
操作数栈
中的操作数值临时存放
。
此时每条指令
均由字节码执行引擎
进行相应的操作。但此时的操作仅仅只是内存层面
的数据操作,指令的计算赋值等依旧需要cpu
去执行实现。
字节码执行引擎
获取需要执行的每条指令
,通过解释执行器/JIT优化
将指令进行翻译
操作,将其翻译成汇编指令
。
字节码执行引擎
是JVM
层面的技术,但是计算机执行命令,只认二进制命令
。
在JVM
中通常使用解释执行器
或者JIT优化器
,将jvm 层面的 字节码
信息翻译成汇编指令
。
汇编指令属于
硬件原语
,此时并不能直接被CPU
进行执行。
依旧需要借用硬件层面
的翻译
操作,将汇编指令
转化为cpu可识别的 二进制指令
。等待CPU的调度执行
,最后影响对应栈中的数据信息
。
具体操作逻辑如下图所示:
这个指令执行完成后,在继续执行下列其他指令。