zoukankan      html  css  js  c++  java
  • klassVtable与klassItable类的介绍

    klassVtable与klassItable类用来实现Java方法的多态,也可以叫动态绑定,是指在应用执行期间通过判断接受对象的实际类型,根据实际类型调用对应的方法。C++为了实现多态,在对象中嵌入了虚函数表vtable,通过虚函数表来实现运行期的方法分派,这在之前介绍HotSpot的二分模型时简单介绍过,这里不再介绍C++的方法分派。

    1、klassVtable类

    C++中的vtable只包含虚函数,非虚函数在编译期就已经解析出正确的方法调用了。Java vtable除了虚方法外还包含了其他的非虚方法。

    vtable中的一条记录用vtableEntry表示,该类在klassVtable.hpp文件中定义,只定义了一个属性Method* _method,所以说此类只是对Method*做了简单包装而已,提供了操作Method对象的方法。

    访问vtable需要通过klassVtable类,该类在klassVtable.hpp文件中定义,提供了操作vtable的方法,如Method* method_at(int i)、int index_of(Method* m)等,其实现都是基于vtable的内存起始地址和内存偏移完成的。

    klassVtable类的定义及属性的声明如下:

    A klassVtable abstracts the variable-length(可变长度) vtable that is embedded in InstanceKlass and ArrayKlass.
    klassVtable objects are used just as convenient transient accessors to the vtable,not to actually hold the vtable data.
    Note: the klassVtable should not be accessed before the class has been verified(until that point, the vtable is uninitialized).
    
    Currently a klassVtable contains a direct reference to the vtable data, and is therefore not preserved across GCs.
    class klassVtable : public ResourceObj {
      KlassHandle  _klass;            // my klass
      int          _tableOffset;      // offset of start of vtable data within klass
      int          _length;           // length of vtable (number of entries)
    
      ...
    }
    

    属性的介绍如下:

    (1)_klass:该vtable所属的klass

    (2)_tableOffset:vtable在klass实例内存中的偏移量

    (3)_length:vtable的长度,即vtableEntry的数量,因为一个vtableEntry实例只包含一个Method*,其大小等于字宽(一个指针的宽度),所以vtable的长度跟vtable以字宽为单位的内存大小相同

    下面介绍一下vtableEntry类。

    vtableEntry类的定义及属性的声明如下:

    class vtableEntry VALUE_OBJ_CLASS_SPEC {
      ...
     private: 
      Method* _method;
      ...
    };
    

    这个类只是对_method进行了简单的封装。 

    vtable表示是由一组变长(前面会有一个字段描述该表的长度)连续的vtableEntry元素构成的数组。其中每个vtableEntry封装了一个Method对象。在类初始化时,HotSpot将复制父类的vtable,然后根据自己定义的方法更新vtableEntry,或向vtable中添加新的vtableEntry对象。当Java方法重写父类方法时,HotSpot将更新vtable中表示被重写方法的vtableEntry,使其指向覆盖后的实现方法;如果是方法重载或者自身新增的方法,HotSpot将按顺序添加到vtable中。尚未提供实现的Java方法也放在了vtable中,因为没有实现,HotSpot没有为这个vtableEntry项分发具体的方法,这和C++的纯虚函数类似,不再赘述。调用类方法时,HotSpot通过ConstantPoolCacheEntry的_f2成员获取vtable中方法的索引,从而取到Method对象以便执行。关于ConstantPoolCacheEntry类及相关属性在后面会详细介绍。

    2、klassItable

    Java itable是Java接口函数表,为了方便查找某个接口对应的方法实现。itable的结构比vtable复杂,除了记录方法地址外还得记录该方法所属的接口类klass。

    itable表由偏移表和方法表两个表组成,这两个表都是变长的。每个offset table entry保存的是类实现的一个接口klassOop和该接口方法表所在的偏移位置;方法表method table entry元素保存的是实现的接口方法,方法在方法表的位置同样是使用ConstantPoolCacheEntry的_f2成员保存的。在初始化itable时,HotSpot将类实现的接口以及实现的方法填写在上述两张表中。接口中的非public方法和abstract方法(在vtable中占一个槽位)不放入itable中。调用接口方法时,HotSpot通过ConstantPoolCacheEntry的_f1成员拿到接口的klassOop,在itable的偏移表中逐一匹配,如果匹配上则获取它的方法表的位置,然后在方法表中通过ConstantPoolCacheEntry的_f2成员找到实现的方法Method。
    类及属性的定义如下:

    class klassItable : public ResourceObj {
     private:
      instanceKlassHandle  _klass;             // my klass
      int                  _table_offset;      // offset of start of itable data within klass (in words)
      int                  _size_offset_table; // size of offset table (in itableOffset entries)
      int                  _size_method_table; // size of methodtable (in itableMethodEntry entries)
      ...
    }
    

    该类包含4个属性:

    (1)_klass:itable所属的Klass

    (2)_table_offset:itable在所属Klass中的内存偏移量

    (3)_size_offset_table:itable中itableOffsetEntry的数量

    (4)_size_method_table:itable中itableMethodEntry的数量

    方法所属的接口类klass地址用itableOffsetEntry表示,类的定义如下:

    class itableOffsetEntry VALUE_OBJ_CLASS_SPEC {
     private:
      Klass*   _interface;
      int      _offset;
      ...
    }
    

    包含两个属性,如下:

    (1) _interface:该方法所属的接口

    (2)_offset:该接口下的第一个方法itableMethodEntry相对于所属Klass的偏移量

    方法地址用itableMethodEntry表示,定义如下:

    class itableMethodEntry VALUE_OBJ_CLASS_SPEC {
     private:
      Method*  _method;
      ...
    }
    

    跟vtableEntry一样,只包含了一个_method属性。

    为什么需要itable,而不是用vtable解决所有问题。

    一个类可以实现多个接口,而每个接口的函数编号是和自己相关的,vtable 无法解决多个对应接口的函数编号问题。而一个子类只能继承一个父亲,子类只要包含父类vtable,并且和父类的函数包含部分编号是一致的,就可以直接使用父类的函数编号找到对应的子类实现函数。 

    相关文章的链接如下:

    1、在Ubuntu 16.04上编译OpenJDK8的源代码 

    2、调试HotSpot源代码

    3、HotSpot项目结构 

    4、HotSpot的启动过程 

    5、HotSpot二分模型(1)

    6、HotSpot的类模型(2)  

    7、HotSpot的类模型(3) 

    8、HotSpot的类模型(4)

    9、HotSpot的对象模型(5)  

    10、HotSpot的对象模型(6) 

    11、操作句柄Handle(7)

    12、句柄Handle的释放(8)

    13、类加载器 

    14、类的双亲委派机制 

    15、核心类的预装载

    16、Java主类的装载  

    17、触发类的装载  

    18、类文件介绍 

    19、文件流 

    20、解析Class文件 

    21、常量池解析(1) 

    22、常量池解析(2)

    23、字段解析(1)

    24、字段解析之伪共享(2) 

    25、字段解析(3)  

    26、字段解析之OopMapBlock(4)

    27、方法解析之Method与ConstMethod介绍  

    28、方法解析

    作者持续维护的个人博客classloading.com

    关注公众号,有HotSpot源码剖析系列文章!

       

    参考文章:

    (1)C++与Java的多态性实现分析

    (2)JVM Anatomy Park #16: 超多态虚调用  https://www.jianshu.com/p/704fce44840f

    (3)The Black Magic of (Java) Method Dispatch  https://shipilev.net/blog/2015/black-magic-method-dispatch/ 

    (4)https://www.zhihu.com/question/34846173?sort=created

    (5)https://www.zhihu.com/question/56936880/answer/152203730

    (6)https://hllvm-group.iteye.com/group/topic/29140

  • 相关阅读:
    获取微信用户在微信小店的订单
    微信网页授权+获取用户基本信息+强制关注+JSSDK分享参数
    微信查询四六级成绩代码
    CURL SSL为6的由来
    阿里云虚拟主机安装禅道总结
    Android手机特殊软件配置
    微信支付参数一致性校验
    微信查询火星天气
    php下curl ssl常用问题
    群发技术-使用python3给微信好友群发消息
  • 原文地址:https://www.cnblogs.com/mazhimazhi/p/13456515.html
Copyright © 2011-2022 走看看