栈帧主要由:局部变量表、操作数栈 、动态链接、方法返回地址
-
局部变量表: 主要用于存放方法参数 和方法内部定义的局部变量,注意 通过jclasslib可以看到 局部变量表存放的第一个变量是 this 指针
-
操作数栈: Java 虚拟机的指令是从操作数栈中而不是从寄存器中取得操作数的
int a = 0; int b = 2; int c = a + b ;
从字节码层来看需要进行以下 步骤:
0 iconst_0 // 将0压入操作数栈
1 istore_1 // 弹出操作数栈栈顶元素,保存到局部变量表第1个位置 (上边说了 第0个位置 会存储 this)
2 iconst_2 // 将2压入操作数栈
3 istore_2 // 弹出操作数栈栈顶元素,保存到局部变量表第2个位置
4 iload_1 // 第1个变量压入操作数栈
5 iload_2 // 第2个变量压入操作数栈
6 iadd // 做运算
7 istore_3 // 弹出操作数栈栈顶元素,保存到局部变量表第3个位置
8 return
- 动态链接 : 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接。我们知道 class文件中 的常量池存在大量的符号引用,字节码中的方法调用指令就医常量池里的指向方法的符号引用作为参数。这些符号引用会在类加载阶段或者第一次使用的时候就被转化为直接引用,这种转化称为静态解析。另一部分在每一次运行期间都会转化为直接引用称为动态引用
调用方法的字节码指令主要是以下几种:
invokestatic:用于调用静态方法。
invokespecial:用于调用私有实例方法、构造器,以及使用 super 关键字调用父类的实例方法或构造器,和所实现接口的默认方法。
invokevirtual:用于调用非私有实例方法。
invokeinterface:用于调用接口方法。
invokedynamic:用于调用动态方法
静态方法、私有方法 构造方法和父类的方法 加上final 修饰的方法,在类加载的时候会将 符号引用转化为直接引用, 这些方法统称为非虚方法,其他的方法 就是虚方法