1、虚拟机栈的结构
Java虚拟机栈早期叫做java栈,每创建一个线程就会对应创建一个虚拟机栈,它的生命周期和线程生命周期一致。虚拟机栈由一个个栈帧组成,每一个栈帧对应一个方法,一次方法调用对应栈帧入栈,一个方法运行结束对应栈帧出栈。栈里面每一个栈帧由局部变量表、操作数栈、动态链接、方法返回地址、附加信息组成。栈的结构如下:
2、虚拟机栈的特点
-
虚拟机栈是一种快速有效的分配储存方式,访问速度仅次于程序计数器
-
虚拟机栈只有两个操作:入栈和出栈
方法调用入栈,方法运行结束出栈
-
虚拟机栈不存在垃圾回收问题
-
虚拟机栈可能会出现以下两种异常:StackOverFlowError、OutOfMemoryError
虚拟机栈的大小既可以设置动态大小,也可以固定不变。当栈大小固定不变时,如果所有栈帧大小加起来大于栈大小,或者一个栈帧比栈大,就会报出StackOverFlowError异常;当栈大小是动态时,栈申请不到更大的栈空间,或者内存大小无法创建一个新的栈,就会报出OutOfMemoryError异常。
3、虚拟机栈运行原理
- 在一个活动线程中,在一个时间点上,只允许有一个活动的栈帧。只有当前执行的方法对应的栈帧是有效的,当前有效的栈帧成为当前栈帧(栈顶栈帧),称为当前栈帧,对应方法称为当前方法,定义这个方法的类称为当前类。
- 如果当前方法调用其它方法,就有新的栈帧被创建并且入栈,成为新的当前栈帧。
- 执行引擎执行的字节码指令只针对于当前栈帧。
- 不能在一个线程的栈帧中引用另一个线程的栈帧。
- 方法有两种返回方式:一种是正常返回,一种抛出异常,这两种方式都会导致栈帧出栈。
下面代码描述方法调用与栈帧活动:
/**
* @author cx
* @date 2022/10/24
*/
public class StackDemo01 {
public static void main(String[] args) {
System.out.println("main方法开始运行...");
method1("main");
System.out.println("main方法运行结束...");
}
static void method1(String name){
System.out.println("method1被" +name+ "方法调用了..." );
method2("method1");
System.out.println("method1运行结束...");
}
static void method2(String name){
System.out.println("method2被" +name+ "方法调用了..." );
method3("method2");
System.out.println("method2运行结束...");
}
static void method3(String name){
System.out.println("method3被" +name+ "方法调用了..." );
System.out.println("method3运行结束...");
}
// console:
// main方法开始运行...
// method1被main方法调用了...
// method2被method1方法调用了...
// method3被method2方法调用了...
// method3运行结束...
// method2运行结束...
// method1运行结束...
// main方法运行结束...
}