上一小结提到了局部变量表和操作数栈,这一节接着总结栈针中的动态链接和方法的调用及方法返回地址
动态连接
- 每一个栈帧内部都包含一个指向运行时常量池中的该栈帧所属方法的引用。而包含这个引用就是为了支持当前方法的代码能够实现动态链接。
- 在字节码文件中,所有变量和方法的引用都作为符号引用,保存在class文件的常量池。
- 动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。
为什么需要常量池?
提供一些符号和常量,便于指令的识别。
一个字节码文件里面如果代码量比较少,但是它包含的信息加载进内存后并不少,如String,类变量,System类,println打印流等信息,通过常量池,将这些信息通通放进去,需要使用的时候通过引用的方式。节省空间,提高效率。
方法的调用
相关概念
- 静态链接:字节码装载进JVM,如果被调用的目标方法编译器可知,且运行期不变,这时会将调用方法的符号引用转换为直接引用,这个过程成为静态链接。
- 动态链接:被调用的方法不能在编译器确定,运行时才将被调方法的符号引用转换为直接引用。称之为动态链接。
- 早期绑定:调用的方法在编译器可知,且运行期保持不变,这时就可直接将方法与所属的类型绑定,称为早期绑定。
- 晚期绑定:如果被调方法编译器不能确定下来,只能根据运行期实际的类型绑定相关方法,称为晚期绑定。
java作为面向对象的编程语言,具备多态特性,自然也具备早期绑定和晚期绑定两种方式。
- 非虚方法:编译器就确定下来,运行期不变时,这种方法为非虚方法,对应指令为invokestatic、invokespecial指令。
- 虚方法:在运行期确定的方法,对应指令为invokevirtual、invokeinterface和invokedynamic指令。
tips
为了提高性能,JVM采用类的方法区建立一个虚方法表来实现,使用索引表来代替查找。
何时创建?
在类加载的链接阶段被创建并初始化。当类变量初始值完成,JVM会把该类的方法表也初始化。
方法返回地址
方法结束的两种方式:
- 正常执行完成。
- 出现未处理的异常,非正常退出。
无论哪种方式,退出方法后都会回到该方法调用的地方。
调用者的pc计数器的值作为返回地址,即下条指令的地址。如果异常退出,返回地址要通过异常表确定,栈帧不保存这部分信息。
两者区别。
异常退出不会给上层调用者(方法)产生任何返回值。