JVM执行引擎工作方式

每当创建一个新的线程时,JVM会为这个线程创建一个JAVA栈,同时会为这个线程分配一个PC寄存器,并且这个PC寄存器会指向这个线程的第一行可执行代码。每当调用一个新方法时会在这个栈上创建一个新的栈帧数据结构,这个栈帧会保留这个方法的一些元信息,如在这个方法中定义的局部变量、一些用来支持常量池的解析、正常方法返回及异常处理机制等等。JVM在调用某些指令时可能需要使用到常量池中的一些常量,或者是获取常量代表的数据或者这个数据指向的实例化对象,而这些信息都存储在所有线程共享的方法区和Java堆中(JDK7起方法区PermGen永久代逐渐被MetaSpace取代)。

Java执行部件图如下图所示。 输入图片说明

那么JVM具体是如何执行的呢?以下面的代码为例:

public class Math{
    public static void main(String[] args){
        int a = 1;
        int b = 2;
        int c = (a + b) * 10;
    }
}

对应到执行引擎的各执行部件如下图所示。 输入图片说明

图中,指令是Java代码经过javac编译后得到的JVM指令,PC寄存器指向下一条该执行的指令地址,局部变量区存储函数运行中产生的局部变量,栈存储计算的中间结果和最后结果。

我们解释一下这十二条指令,分别是常数1入栈,将栈顶元素移入本地变量1存储,常数2入栈,将栈顶元素移入本地变量2存储,本地变量1入栈,本地变量2入栈,弹出栈顶两个元素相加然后结果入栈,将10入栈,栈顶两个元素弹出并相乘然后结果入栈,栈顶元素移入本地变量3存储,返回。 上图是地址为9的指令执行完毕后的状态,PC寄存器指向地址10。地址为9的指令将栈顶两个元素弹出并相乘然后将结果入栈,所以操作栈中计算结果30为栈顶元素。执行地址10的指令后,30被保存在本地变量3中,故局部变量区地址为3的区块将保存30。

在Java程序的执行过程中,栈操作是无处不在的。所以我们可以想到,在Java中,我们不仅可以自定义栈数据结构从而显式调用栈,还可以通过JVM的运行机制隐式调用栈。可能你已经想到了,我们可以使用递归函数的形式,来利用JVM的栈已达到栈这种后入先出的数据结构在计算中获得的效果。

当A函数调用B函数时,JVM会为B函数在栈中压如一个新的栈帧,并将这个栈帧设为当前栈帧,函数B运行结束时,将栈帧弹出撤销,将B的返回结果压入栈的栈顶,PC寄存器恢复调用栈的下一条指令地址。然后A函数执行完毕,执行return命令如果当前线程对应的栈中没有了栈帧,这个Java栈也将会被JVM撤销。

猜你喜欢

转载自my.oschina.net/chenxuanli/blog/1790628