一 运行时栈帧结构 : 栈帧分配多少内存,与运行时无关
1: 局部变量表 : 容量以slot 槽为单位
一个slot 占用32位长度的内存空间,可以存的类型有boolean、byte、char、short、int、float、reference、retuanaddress .
reference 类型 : 表示对象引用、returnaddress 类型 指向一条字节码指令的地址
二个slot 可以存long double 类型
2: 操作数栈 : 后入先出
当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令在操作数栈中,入栈和出栈。
3: 动态链接
栈帧中包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接
class 文件常量池中存在大量的符号引用,字节码中的方法调用指令就是用常量池中指向方法的符号引用作为参数。
静态解析: 符号引用会在类加载时转化为直接引用
动态链接: 每次运行时转化再转化为直接引用
4: 方法返回地址
1、方法退出后,都需要返回到方法被调用的位置,程序才能继续执行。
二、方法调用 : 任务是确定被调用方法的版本,暂时还不涉及方法内部的具体运行过程。
1、解析(静态)将class文件符号引用转化为直接引用 (因为符号引用不是实际的入口地址)
有两种方法, 静态方法: 与类型直接关联,私有方法: 外部不可被访问 ,都它们都适合在类加载阶段解析。
解析调用一定是个静态的过程,在编译期间就完全确定。
2、分派 (动态和静态): 分派调用将会揭示多态性的一些最基本体现,重载和重写 ,关心虚拟机如何确定正确的目标方法。
(1) 静态分派 (重载方法): 依赖静态类型来定位方法执行版本的分派动作
(2)动态分派 (重写): 依赖实际类型来定位方法执行 版本的分派动作
通过在方法区上的虚方法表来实现动态分派
(3)方法的接受者和方法参数(宗量): 单分派是根据一个宗量,多分派多个
3、动态语言 : 它的类型检查过程时在运行期而不是编译期。
三、问题 虚拟机是如何执行方法中的字节吗指令的?下面是几种方法
基于栈的字节码解释执行引擎
1、 解释执行
基于栈的指令集与基于寄存器的指令集
1+1
1、基于栈的指令集
iconst_1
iconst_1
iadd
istore_0
2、基于寄存器
mov eax,1
add eax,1
3、基于栈的解释器执行过程
列子源码
public int calc(){
int a = 100;
int b = 200;
int c = 300;
return (a+b) *c
}
字节吗
public int calc(){
code :
stack =2,locals=4,args_size=1
0: bipush 100
2: istore_1
3: sipush 200
6: istore_2
7: sipush 300
10: istore_3
11: iload_1
12: iload_2
13: iadd
14:iload_3
15:imul
16:ireturn
}