HotSpot的類模型(4)
- 2020 年 7 月 9 日
- 筆記
我們繼續接著上一篇 HotSpot的類模型(3)分析,這次主要分析表示java數組的C++類。
4、ArrayKlass類
ArrayKlass繼承自Klass,是所有數組類的抽象基類,類及重要屬性的定義如下:
class ArrayKlass: public Klass { ... private: int _dimension; // This is n'th-dimensional array. Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present). Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present). int _vtable_len; // size of vtable for this klass oop _component_mirror; // component type, as a java/lang/Class ... }
在Klass的基礎上增加的屬性如下表所示。
欄位 | 作用 |
_dimension | int類型,表示數組的維度,記為n |
_higher_dimension | Klass指針,表示對n+1維數組Klass的引用 |
_lower_dimension | Klass指針,表示對n-1維數組Klass的引用 |
_vtable_len | int類型, 虛函數表的長度 |
_component_mirror | oop, 數組元素對應的java/lang/Class對象的Oop |
_vtable_len的值為5,因為數組是引用類型,父類為Object類,而Object類中有5個虛方法可被用來繼承和重寫,如下:
- void finalize()
- boolean equals(Object)
- String toString()
- int hashCode()
- Object clone()
_dimension、_higher_dimension與_lower_dimension對於一維及多維數組的描述非常重要,屬性值的設置相對簡單,這裡不在介紹。
5、ArrayKlass類的子類
(1)TypeArrayKlass類
TypeArrayKlass是ArrayKlass的子類,用於表示數組元素是基本類型的數組
class TypeArrayKlass : public ArrayKlass { ... private: jint _max_length; // maximum number of elements allowed in an array ... }
_max_length表示該數組允許的最大長度。
數組類和普通類不同,數組類沒有對應的Class文件,所以數組類是直接被虛擬機創建的。HotSpot在初始化時就會創建好8個基本類型的一維數組對象TypeArrayKlass。之前在講解HotSpot啟動時講到過,調用initializeJVM()方法初始化HotSpot,這個方法會最終調用到Universe::genesis()方法,在這個方法中初始化基本類型的一維數組對象TypeArrayKlass。例如初始化boolean類型的一維數組,調用語句如下:
_boolArrayKlassObj = TypeArrayKlass::create_klass(T_BOOLEAN, sizeof(jboolean), CHECK);
其中_boolArrayKlassObj是聲明在universe.cpp文件中的全局變數,如下:
Klass* Universe::_boolArrayKlassObj = NULL;
調用TypeArrayKlass::create_klass()方法創建TypeArrayKlass對象,具體就是調用TypeArrayKlass::create_klass()方法來完成,方法的實現如下:
TypeArrayKlass* TypeArrayKlass::allocate(ClassLoaderData* loader_data, BasicType type, Symbol* name, TRAPS) { assert(TypeArrayKlass::header_size() <= InstanceKlass::header_size(), "array klasses must be same size as InstanceKlass"); int x = TypeArrayKlass::header_size(); int size = ArrayKlass::static_size(x); // 調用的構造函數在下面 return new (loader_data, size, THREAD) TypeArrayKlass(type, name); }
非常類似於InstanceKlass等對象的創建,首先獲取需要記憶體的大小size,然後通過重載new運算符完成對象記憶體分配後,調用TypeArrayKlass初始化一些屬性,TypeArrayKlass的構造函數如下:
TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name) { int lh = array_layout_helper(type); set_layout_helper(lh); assert(oop_is_array(), "sanity"); assert(oop_is_typeArray(), "sanity"); set_max_length(arrayOopDesc::max_array_length(type)); // 設置數組的最大長度 ... }
下面詳細介紹一下對_layout_helper屬性的設置。調用Klass::array_layout_helper()方法獲取_layout_helper屬性的值
jint Klass::array_layout_helper(BasicType etype) { assert(etype >= T_BOOLEAN && etype <= T_OBJECT, "valid etype"); // Note that T_ARRAY is not allowed here. int hsize = arrayOopDesc::base_offset_in_bytes(etype); // hsize表示數組對象頭部大小 int esize = type2aelembytes(etype); // 對應類型存儲所需要的位元組數 bool isobj = (etype == T_OBJECT); int tag = isobj ? _lh_array_tag_obj_value : _lh_array_tag_type_value; int esz = exact_log2(esize); int lh = array_layout_helper(tag, hsize, etype, esz); return lh; }
關於_layout_helper在之前已經介紹過,由於T_BOOLEAN為基本類型,所以值為0xC0;hsize調用arrayOopDesc::base_offset_in_bytes()方法獲取,值為16,後面在講解arrayOopDesc時會介紹,數組對象其實是由對象頭、對象欄位數據和對齊填充組成,而這裡獲取的就是對象頭的大小;esize表示對應類型存儲所需要的位元組數,對於T_BOOLEAN來說,只需要1個位元組即可,所以esz為0。最後調用array_layout_helper()方法按照約定組合成一個int類型的數字即可。array_layout_helper()方法的實現如下:
static jint array_layout_helper(jint tag, int hsize, BasicType etype, int log2_esize) { return (tag << _lh_array_tag_shift) // 左移30位 | (hsize << _lh_header_size_shift) // 左移16位 | ((int)etype << _lh_element_type_shift) // 左移1位 | (log2_esize << _lh_log2_element_size_shift); // 左移0位 }
另外還有對_component_mirror屬性的設置。對於一維基本類型的數組來說,這個值是java.lang.Class對象。Class對象使用oop對象來表示,調用java_lang_Class::create_basic_type_mirror()方法獲取_component_mirror屬性的值,通過java_lang_Class::create_mirror()方法完成屬性的設置。例如獲取boolean類型的屬性值,調用語句如下:
void Universe::initialize_basic_type_mirrors(TRAPS) { ... _bool_mirror = java_lang_Class::create_basic_type_mirror("boolean",T_BOOLEAN, CHECK); ... }
方法create_basic_type_mirror()的實現如下:
oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser) oop java_class = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->allocate_instance(NULL, CHECK_0); if (type != T_VOID) { Klass* aklass = Universe::typeArrayKlassObj(type); assert(aklass != NULL, "correct bootstrap"); set_array_klass(java_class, aklass); // 設置表示基本類型數組的TypeArrayKlass的 } return java_class; }
通過InstanceMirrorKlass對象(表示java.lang.Class類)來創建oop(表示java.lang.Class對象),所以_component_mirror最終設置的就是這個oop。引用類型組成的一維或多維數組的基本元素可以使用Klass對象來表示,如對於下面即將要介紹的Object[]來說,元素類型為Object,所以可以使用InstanceKlass來表示;基本類型組成的一維或多維數組的基本元素沒有對應的Klass對象,所以只能使用Class對象來描述boolean、int等,這樣就會與表示Class對象的InstanceMirrorKlass對象產生關係,相關屬性最終的值如下所示。
TypeArrayKlass._component_mirror=InstanceMirrorKlass InstanceMirrorKlass._array_klass=TypeArrayKlass
其它的屬性設置很簡單,這裡不在介紹。
(2)ObjArrayKlass類
ObjArrayKlass是ArrayKlass的子類,用於表示數組元素是類或者數組
class ObjArrayKlass : public ArrayKlass { ... private: Klass* _element_klass; // The klass of the elements of this array type Klass* _bottom_klass; // The one-dimensional type (InstanceKlass or TypeArrayKlass) ... }
該類新增了2個屬性,如下:
- _element_klass:數組元素對應的Klass引用,如果是多維數組,對應數組元素的ObjArrayKlass的引用
- _bottom_klass:一維數組的類型,可以是InstanceKlass或者TypeArrayKlass。一維基本類型數組為TypeArrayKlass,而二維基本類型數組就會使用ObjArrayKlass來表示,所以其_bottom_klass會是TypeArrayKlass。
HotSpot在Universe::genesis()方法中創建Object數組,如下:
InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::Object_klass()); _objectArrayKlassObj = ik->array_klass(1, CHECK); // 調用表示Object類的InstanceKlass類的array_klass()方法
調用array_klass()方法時傳遞的參數1表示創建一維數組。調用表示Object類的InstanceKlass對象的方法創建的,所以Object數組的創建要依賴於InstanceKlass對象(表示Object類)進行創建。
最終表示Object類的InstanceKlass與表示一維數組Object[]的ObjArrayKlass之間的相關屬性如下:
ObjArrayKlass._element_klass=InstanceKlass ObjArrayKlass._bottom_klass=InstanceKlass InstanceKlass._array_name="[Ljava/lang/Object;" InstanceKlass._array_klasses=ObjArrayKlass
ObjArrayKlass中其它的屬性設置也並不複雜,這裡不在介紹。
相關文章的鏈接如下:
1、在Ubuntu 16.04上編譯OpenJDK8的源程式碼
關注公眾號,有HotSpot源碼剖析系列文章!