虚拟机动态分派的实现
如果问Java虚拟机“具体如何做到”的,答案则可能因各种虚拟机的实现不同会有些差别。
动态分派是执行非常频繁的动作,而且动态分派的方法版本选择过程需要运行时再接收者类型的方法元数据中搜索合适的目标方法,因此Java虚拟机实现基于执行性能的考虑,真正运行时一般不会如此频繁地反复搜索类型元数据。面对这种情况,一种基础而且常见的优化手段是为类型在方法区中建立一个虚方法表(Virtual Method Table,也称为vtable,与此对应的,在invokeinterface执行时也会用到接口方法表——Interface Method Table,简称itable),使用虚方法表索引来代替元数据查找以提高性能。
方法表结构.png虚方法表中存放着各个方法的实际入口地址。如果某个方法种在子类中没有被重写,那子类的虚方法表中的地址入口和父类相同方法的地址入口是一致的,都是指向父类的实现入口。如果子类中重写了这个方法,子类虚方法表中的地址也会被替换为指向子类实现版本的入口地址。
为了程序实现方便,具有相同签名的方法,在父类、子类的虚方法表中都应当具有一样的索引序号,这样当类型转换时,仅需变更查找的虚方法表,就可以从不同的虚方法表中按索引转换出所需的入口地址。虚方法表一般在类加载的连接阶段进行初始化,准备子类的变量初始值后,虚拟机会把该类的虚方法表也一同初始化完毕。
查虚方法表是分派调用的一种优化手段,由于Java对象里面的方法默认(即不使用final修饰)就是虚方法,虚拟机除了使用虚方法表之外,为了进一步提供性能,还会使用类型继承关系分析(Class Hierarchy Analysis,CHA)、守护内联(Guarded Inlining)、内联缓存(Inline Cache)等多种非稳定的激进优化来争取更大的性能空间。
《深入理解Java虚拟机》第三版 学习笔记
网友评论