栈帧是虚拟机运行时数据区中的虚拟机栈的栈元素,栈帧存储了方法的局部变量表,操做数栈,动态链接,方法返回地址,在编译程序代码的时候,栈帧中须要多大的局部变量表、多深的操做数栈都已经彻底肯定了,而且写入到方法表的Code属性之中。
java
其最大容量由方法的Code属性,max_locals肯定,局部变量表的容量以变量槽(Slot)为最小单位,Long和Double占用两个空间,其读写是非原子性的,其会占用n与n+1两个Slot,不容许采用任何方式单独访问其中的一个Slot。性能
在方法执行时,虚拟机是使用局部变量表来完成参数值到变量表的传递,若是执行的是实例方法,那么局部变量表第0位索引的Slot默认是用于传递方法所属的对象实例的引用,其他参数从索引1开始占用Slot,参数表分配完毕后,再根据方法体内部定义的变量顺序和做用域分配其他的Slot,为了尽量的节省栈帧空间,局部变量表中的Solt是能够重用的,当PC计数器的值,已经超出方法体中定义的变量的做用域时,其占用的Slot会被其余做用域的变量重用。对象
其最大深度由方法的Code属性的max_stacks决定,有些虚拟机实现上,会让相邻的两个栈帧出现一些 共享部分,方便方法调用之间共享数据。blog
每一个栈帧都包含一个指向运行时常量池中该帧所属方法的引用,这个引用是为了支持方法调用过程当中的动态链接。继承
当一个方法执行之后,只有两种方式能够退出这个方法,一个是执行引擎遇到一个返回的字节码指令,这时候可能会有返回值传递给上层的方法调用者,这种退出方法被称为正常完成出口,另外一种退出方式是,在方法的执行过程当中遇到了异常,只要在本方法的异常表中没有搜索到匹配的异常处理器,就会致使方法退出,这种退出方式被称为异常完成出口,这种方式是不会给它的上层调用者返回任何返回值的。索引
不管任何方式退出,都须要返回到方法被调用的位置,程序才能继续执行,因此方法退出时会恢复上层方法的局部变量表和操做数栈,把返回值压入调用者的操做数栈,调整PC至下一条指令地址。ip
方法调用阶段惟一的任务就是肯定被调用方法的版本作用域
方法的调用包括解析与分派两种方式虚拟机
动态分派的解析过程(invokevirtual指令为例):编译
出于性能的考虑,会为类在方法区创建一个虚方法表,使用虚方法表索引来代替元数据查找以提升性能
本文参考:《深刻理解Java虚拟机》