今天看啥  ›  专栏  ›  gzss

java虚拟机动态分派的实现

gzss  · 简书  ·  · 2019-07-26 22:49

前面简单聊了一下Java的分派过程,作为对虚拟机概念模型的解析基本上已经OK,他已经解决了在虚拟机中“会做什么”这个问题,但是虚拟机“具体是如何做到的”,可能各种虚拟机的实现都会有些差别。

由于动态分派是非常频繁的操作,而且动态分派的方法版本选择过程需要运行时在类的方法元数据中搜索合适的目标方法,因此在虚拟机的实际实现中基于性能的考虑,大部分实现都不会真正的进行如此频繁的搜索。面对这种情况,最长用的“稳定优化手段就是”为类在方法区中建立一个虚方发表(Vritual Method Table,也成为vtable,与此对应的,在invokeinterface执行时也会用到接口方发表--Interface Method Table,简称itable),使用虚方发表索引来代替元数据查找以提高性能。我们看一下下面这段代码以及他所对应的虚方发表结构:


虚方发表中存放着各个方法的实际入口地址。如果某个方法在子类中没有被重写,那子类的虚方法表里面的地址入口和父类相同方法的地址入口是一致的,都指向父类的实现入口,如果子类中重写了这个方法,子类方法表中的地址将会替换为指向子类实现版本的入口地址。如上图中Son重写了来自Father的全部方法,因此Son的方法表没有指向Father类型数据的箭头。但是Son和Father都没有重写来自Object的方法,所以他们的方法表中所有从Object继承来的方法都指向了object的数据类型。

为了程序上实现方便,具有相同签名的方法,在父类、子类的虚方法表中都应单具有一样的索引序号,这样当类型变换时,仅需要变更查找的方发表,就可以从不同的虚方法表中按索引转换出所需要的入口地址。

方发表一般在类加载的连接阶段进行初始化,准备了类的变量初始值后,虚拟机会把该类的方发表也初始化完毕。

方发表是分派调用的“稳定优化”手段,虚拟机除了使用方法表之外,在条件允许的情况下,还会使用内联缓存(Inline cache)和基于“类型继承关系分析”(Class Hierarchy Analysis , CHA)技术的守护内联(Guarded Inlining)两种非稳定的“激进优化”手段来获得更高的性能。




原文地址:访问原文地址
快照地址: 访问文章快照