简介
栈帧是用来存储数据和部分过程结果的数据结构,同时也用来处理动态链接、方法返回值和异常分派。栈帧是存储在Java虚拟机栈中。
生命周期
栈帧随着方法调用而创建,随着方法结束而销毁(无论是正常完成还是异常完成即抛出异常)。
组成部分
每个栈帧都有各自的本地变量表、操作数栈和指向当前方法所属的类的运行时常量池的引用。注意这里是运行时常量池的引用,重点是引用。
注意点
- 正在执行方法的栈帧称为当前栈帧
- 当前栈帧对应的方法称为当前方法
- 定义这个方法的类称为当前类
- 栈帧是线程私有的数据,不可能在一个栈帧中引用另外一个线程的栈帧
组成
局部变量表
每个栈帧内部都包含一组称为局部变量表的变量列表。局部变量表用于方法调用时的参数传递。
当调用类方法时,它的参数将于依次传递到局部变量表从0开始的连续位置上。
而当调用实例方法时,第0个局部变量必定用于存储实例方法所在的对象的引用(this),后续参数将会传递到局部变量表从1开始的连续位置上。
操作数栈
每个栈帧内部都会包含一个称为操作数栈的后入先出(LIFO)栈。其最大深度在编译器就决定了。
刚创建的操作数栈是空的。而一般JVM的运算就是通过一系列的指令从局部变量表或者对象实例的字段入栈和出栈完成的,同时操作数栈也用于准备调用方法的参数与接受方法返回的结果。
动态链接
动态链接其实就是依赖每个栈帧中包含的当前方法所在类的运行时常量池的引用,通过使用符号引用转化为对实际方法的直接引用实现的。
方法调用正常完成
方法调用正常完成是指不抛出任何异常(包括主动throw的异常)。当方法调用正常的时候,它会返回一个值给调用它的方法,此时当前栈帧会恢复调用者的局部变量表和操作数栈,递增程序计数器以及跳过刚才执行的方法调用指令等。
方法调用异常完成
方法调用异常完成是指方法的执行过程中,某些指令的执行导致JVM抛出异常且该方法无法处理或者是自动throw异常(对应athrow指令),需要注意此时一定不会有方法返回值返回给调用者。