HotSpot的類模型(4)

咱們繼續接着上一篇 HotSpot的類模型(3)分析,此次主要分析表示java數組的C++類。html

四、ArrayKlass

ArrayKlass繼承自Klass,是全部數組類的抽象基類,類及重要屬性的定義以下:  java

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的基礎上增長的屬性以下表所示。bootstrap

字段 做用
_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對於一維及多維數組的描述很是重要,屬性值的設置相對簡單,這裏不在介紹。函數

五、ArrayKlass類的子類

(1)TypeArrayKlass類oop

TypeArrayKlass是ArrayKlass的子類,用於表示數組元素是基本類型的數組this

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文件中的全局變量,以下:component

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中其它的屬性設置也並不複雜,這裏不在介紹。

 

相關文章的連接以下:

一、在Ubuntu 16.04上編譯OpenJDK8的源代碼 

二、調試HotSpot源代碼

三、HotSpot項目結構 

四、HotSpot的啓動過程 

五、HotSpot二分模型 (1)

六、HotSpot的類模型(2)  

七、HotSpot的類模型(3) 

關注公衆號,有HotSpot源碼剖析系列文章!  

相關文章
相關標籤/搜索