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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM