klassVtable与klassItable类用来实现Java方法的多态,也可以叫动态绑定,是指在应用执行期间通过判断接受对象的实际类型,根据实际类型调用对应的方法。C++为了实现多态,在对象中嵌入了虚函数表vtable,通过虚函数表来实现运行期的方法分派,这在之前介绍HotSpot的二分模型时简单介绍过,这里不再介绍C++的方法分派。
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类及相关属性在后面会详细介绍。
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的源代码
13、类加载器
14、类的双亲委派机制
15、核心类的预装载
16、Java主类的装载
17、触发类的装载
18、类文件介绍
19、文件流
20、解析Class文件
21、常量池解析(1)
22、常量池解析(2)
23、字段解析(1)
24、字段解析之伪共享(2)
25、字段解析(3)
28、方法解析
作者持续维护的个人博客classloading.com。
关注公众号,有HotSpot源码剖析系列文章!
参考文章:
(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
原文:https://www.cnblogs.com/mazhimazhi/p/13456515.html