★
查看具体的执行图示,需要先了解一下 java 线程执行的地方,Java 每一个线程执行字节码指令都是在 jvm 虚拟机栈中完成
”
1.JVM 虚拟机栈
每一条 JVM 线程都有自己私有的 JVM 栈(Java Virtual Machine Stack),这个栈与线程同时创建,用于存储帧(Frames)。JVM 栈的作用与传统语言(例如 C 语言)中的栈非常类似,就是用于存储局部变量与一些过程结果的地方。另外,它在方法调用和返回中也扮演了很重要的角色。因为除了帧的出栈和入栈之外,JVM 栈不会再受其他因素的影响,所以帧可以在堆中分配,JVM 栈所使用的内存不需要保证是连续的。
栈帧
每一个方法被执行时都会创建一个栈帧,每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
帧(Frames)是用来存储数据和部分结果,由三部分组成:局部变量、操作数栈和帧数据区。
局部变量区与操作数栈的大小要视相应方法而定,他们都是按字长来计算的。编译器在编译时就确定了这些值并存放在 class 文件中。而帧数据区的大小则依赖于具体实现。
当虚拟机调用一个 Java 方法时,他从对应类的类型信息中得到此方法的局部变量区和操作数栈大小,并根据此来分配帧内存,最后压入到栈中。
局部变量区:
局部变量表的大小在编译期间分配,方法运行时不会改变大小。
操作数栈:
与局部变量区相同,操作数栈也是被组织成一个以字长为单位的数组。但是与前者不同的是,他不是通过索引来访问,而是通过标准的栈操作(入栈,出栈)来访问的。比如,如果某个指令把一个值压入到操作数栈中,稍后另一个指令就可以弹出这个值来使用。虚拟机在操作数栈中存储数据的方式与局部变量区相同。
虚拟机把操作数栈作为他的工作区,大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈中。比如,iadd(2 个 int 型变量相加) 指令就要从操作数栈中弹出两个整数,执行加法运算,然后将结果压回操作数栈中。
帧数据区:
除了局部变量区和操作数栈外,帧还需要以下数据来支持常量池解析、正常方法返回以及异常派发机制等内容,这些信息就保存在帧数据区。
Java 虚拟机中的大多数指令都设置及到常量池入口,有些指令仅仅是从常量池中读取数据(int,long,float,double 和 String)后压入栈中;另有一些指令使用常量池的数据来指示要实例化的类型或数组、要访问的自动或要调用的方法;还有些指令需要常量池中的数据才能确定某个对象是否属于某个类或实现了某个接口。每当虚拟机要执行某个需要用到常量池数据的指令时,他都会通过帧数据区中指向常量池的指针来访问它。
2.实战演示:
Test.java
public class Test {
public static void test(){
int a = 1;
int b = 2;
int c = a+b;
int d = 5;
int e = d*c;
}
}
在虚拟机栈的执行流程如图