在不同的虚拟机实现里面,有可能是解释执行或编译执行
运行时栈帧结构
栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,是虚拟机运行时数据区中的虚拟机栈的栈元素
栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息
每一个方法从调用开始至执行完成的过程,都对应一个栈帧在虚拟机栈里从入栈到出栈的过程
一个线程中的方法调用链可能很长,很多方法都同时处于执行状态,只有位于栈顶的栈帧才是有效的,称为当前栈帧
与这个栈帧相关联的方法称为当前方法
局部变量表:
局部变量表是一组变量值存储空间,由于存放方法参数和方法内部定义的局部变量
在java程序编译为Class文件时,就在方法的Code属性中确定了该方法所需要分配的局部变量表的最大容量
局部变量表的容量以变量槽为最小单位
在方法执行时,虚拟机是使用局部变量表完成参数值到参数变量列表的传递过程
操作数栈:
操作数栈也称为操作栈,它是一个后入先出栈,
当方法开始执行时,操作数栈为空,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容
动态连接:
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接
方法返回地址:
两种退出方法的方式:
1 执行引擎遇到任意一个方法返回的字节码指令,正常完成出口
2 方法执行过程中出现异常,并且这个异常没有在方法体内得到处理,异常完成出口
附加信息:
方法调用
方法调用不等于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本
解析:
所有方法调用中的目标方法在Class文件里面都是一个常量池中的符号引用,
在类加载的解析阶段,会将符号引用转化直接引用,前提是:方法在程序运行之前就有一个可确定的调用版本,
并且在运行期是不可改变的
在java语言中,符合“编译器可知,运行期不可变”这个要求的方法,主要包括静态方法和私有方法两大类
分派:
静态分派:
依赖静态类型来定位方法执行版本的分派动作称为静态分派,典型应用是方法重载
动态分派:
在运行期根据实际类型确定方法执行版本的分派过程称为动态分派
虚拟机动态分派的实现
由于动态分派是非常频繁的动作,因此为类的方法区中建立一个虚方法表,
虚方法表中存放着各个方法的实际入口地址,如果子类没有重写父类的方法,那么入口是一致的,
如果子类重写了,那么子类方法表中的地址将会替换为指向子类实现版本的入口地址