HotSpot的類模型(3)

上一篇 HotSpot的類模型(2) 介紹了類模型的基礎類Klass的重要屬性及方法,這一篇介紹一下InstanceKlass及InstanceKlass的子類。html

二、InstanceKlass類

每一個InstanceKlass對象表示一個具體的Java類(這裏的Java類不包括Java數組)。InstanceKlass類及重要屬性的定義以下:java

class InstanceKlass: public Klass {
 ...

 protected:
  // Annotations for this class
  Annotations*       _annotations;
  // Array classes holding elements of this class.
  Klass*             _array_klasses;
  // Constant pool for this class.
  ConstantPool*     _constants;
  // The InnerClasses attribute and EnclosingMethod attribute. The
  // _inner_classes is an array of shorts. If the class has InnerClasses
  // attribute, then the _inner_classes array begins with 4-tuples of shorts
  // [inner_class_info_index, outer_class_info_index,
  // inner_name_index, inner_class_access_flags] for the InnerClasses
  // attribute. If the EnclosingMethod attribute exists, it occupies the
  // last two shorts [class_index, method_index] of the array. If only
  // the InnerClasses attribute exists, the _inner_classes array length is
  // number_of_inner_classes * 4. If the class has both InnerClasses
  // and EnclosingMethod attributes the _inner_classes array length is
  // number_of_inner_classes * 4 + enclosing_method_attribute_size.
  Array<jushort>*   _inner_classes;
 
  // Array name derived from this class which needs unreferencing
  // if this class is unloaded.
  Symbol*           _array_name;
 
  // Number of heapOopSize words used by non-static fields in this klass
  // (including inherited fields but after header_size()).
  int               _nonstatic_field_size;
  int               _static_field_size;    // number words used by static fields (oop and non-oop) in this klass
  // Constant pool index to the utf8 entry of the Generic signature,
  // or 0 if none.
  u2                _generic_signature_index;
  // Constant pool index to the utf8 entry for the name of source file
  // containing this klass, 0 if not specified.
  u2                _source_file_name_index;
  u2                _static_oop_field_count;// number of static oop fields in this klass
  u2                _java_fields_count;    // The number of declared Java fields
  int               _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks
 

  u2                _minor_version;  // minor version number of class file
  u2                _major_version;  // major version number of class file
  Thread*           _init_thread;    // Pointer to current thread doing initialization (to handle recusive initialization)
  int               _vtable_len;     // length of Java vtable (in words)
  int               _itable_len;     // length of Java itable (in words)
  OopMapCache*      volatile _oop_map_cache;   // OopMapCache for all methods in the klass (allocated lazily)
  JNIid*            _jni_ids;              // First JNI identifier for static fields in this class
  jmethodID*        _methods_jmethod_ids;  // jmethodIDs corresponding to method_idnum, or NULL if none
  nmethodBucket*    _dependencies;         // list of dependent nmethods
  nmethod*          _osr_nmethods_head;    // Head of list of on-stack replacement nmethods for this class

 
  // Class states are defined as ClassState (see above).
  // Place the _init_state here to utilize the unused 2-byte after
  // _idnum_allocated_count.
  u1                _init_state;                    // state of class
  u1                _reference_type;                // reference type
 

  // Method array.
  Array<Method*>*   _methods;
  // Default Method Array, concrete methods inherited from interfaces
  Array<Method*>*   _default_methods;
  // Interface (Klass*s) this class declares locally to implement.
  Array<Klass*>*    _local_interfaces;
  // Interface (Klass*s) this class implements transitively.
  Array<Klass*>*    _transitive_interfaces;

  // Int array containing the vtable_indices for default_methods
  // offset matches _default_methods offset
  Array<int>*       _default_vtable_indices;
 
  // Instance and static variable information, starts with 6-tuples of shorts
  // [access, name index, sig index, initval index, low_offset, high_offset]
  // for all fields, followed by the generic signature data at the end of
  // the array. Only fields with generic signature attributes have the generic
  // signature data set in the array. The fields array looks like following:
  //
  // f1: [access, name index, sig index, initial value index, low_offset, high_offset]
  // f2: [access, name index, sig index, initial value index, low_offset, high_offset]
  //      ...
  // fn: [access, name index, sig index, initial value index, low_offset, high_offset]
  //     [generic signature index]
  //     [generic signature index]
  //     ...
  Array<u2>*        _fields;
 
  // embedded Java vtable follows here
  // embedded Java itables follows here
  // embedded static fields follows here
  // embedded nonstatic oop-map blocks follows here
  // embedded implementor of this interface follows here
  //   The embedded implementor only exists if the current klass is an
  //   iterface. The possible values of the implementor fall into following
  //   three cases:
  //     NULL: no implementor.
  //     A Klass* that's not itself: one implementor.
  //     Itsef: more than one implementors.
  // embedded host klass follows here
  //   The embedded host klass only exists in an anonymous class for
  //   dynamic language support (JSR 292 enabled). The host class grants
  //   its access privileges to this class also. The host class is either
  //   named, or a previously loaded anonymous class. A non-anonymous class
  //   or an anonymous class loaded through normal classloading does not
  //   have this embedded field.
  
  ...
}

重要屬性的介紹以下表所示。bootstrap

字段名 做用
_annotations Annotations類型的指針,保存該類使用的全部註解
_array_klasses

數組元素爲該類的數組Klass指針,例如ObjArrayKlass是對象數組且元素類型爲Object,數組

那麼表示Object類的InstanceKlass對象的_array_klasses就是指向ObjArrayKlass的指針ide

_array_name

以該類爲數組元素的數組的名字,如"[Ljava/lang/Object;"函數

_constants ConstantPool類型的指針,用來保存類的常量池信息
_inner_classes 用一個jushort數組保存當前類的InnerClasses屬性和EnclosingMethod屬性
_nonstatic_field_size 非靜態字段須要佔用的內存大小 ,以字爲單位
_static_field_size 靜態字段須要佔用的內存大小 ,以字爲單位
_generic_signature_index

保存此類的Generic signature在常量池中的索引oop

_source_file_name_index 保存此類的源文件名在常量池中索引
_static_oop_field_count 此類包含的靜態引用類型字段的數量
_java_fields_count 字段總數量
_nonstatic_oop_map_size 非靜態的oop map block的內存大小,以字爲單位
_minor_version 類的次版本號
_major_version 類的主版本號
_init_thread 執行此類初始化的Thread指針
_vtable_len Java虛函數表(vtable)所佔用的內存大小,以字爲單位
_itable_len Java接口函數表(itable)所佔用的內存大小,以字爲單位
_oop_map_cache OopMapCache指針,該類的全部方法的OopMapCache
_jni_ids/_methods_jmethod_ids JNIid指針與jmethodID指針,這2個指針對於JNI方法操做屬性和方法很是重要,在介紹JNI時會詳細介紹。
_dependencies nmethodBucket指針,依賴的本地方法,以根據其_next屬性獲取下一個nmethod
_osr_nmethods_head 棧上替換的本地方法鏈表的頭元素
_init_state

表示類的狀態,爲枚舉類型ClassState,定義了以下常量值:ui

  • allocated(已分配內存)
  • loaded(從class文件讀取加載到內存中)
  • linked(已經成功連接和校驗)
  • being_initialized(正在初始化)
  • fully_initialized(已經完成初始化)
  • initialization_error(初始化異常)
_reference_type 引用類型
_methods 保存方法的指針數組
_default_methods 保存方法的指針數組,從接口繼承的默認方法
_local_interfaces 保存接口的指針數組,直接實現的接口Klass
_transitive_interfaces 保存接口的指針數組,包含_local_interfaces和經過繼承間接實現的接口
_default_vtable_indices 默認方法在虛函數表中的索引
_fields

類的字段屬性,每一個字段的6個屬性access,、name index、sig index、initial value index、low_offset、high_offset組成一個元組,this

access表示訪問控制屬性,根據name index能夠獲取屬性名,根據initial value index能夠獲取初始值,根據low_offset與指針

high_offset能夠獲取該屬性在內存中的偏移量。另外保存完全部屬性以後還可能會保存泛型簽名信息。

有了InstanceKlass與Klass中定義的這些屬性足夠用來保存Java類元信息。在後續的類解析中會看到對相關變量的屬性填充操做。除了保存類元信息外,此類還有另一個重要的功能,即支持方法分派,主要是經過Java虛方法表和Java接口函數表來完成的,不過C++並不像Java同樣,保存信息時非要在類中定義出相關屬性,C++只是在分配內存時爲要存儲的信息分配好特定的內存,而後直接經過內存偏移來操做便可。

接下來幾個屬性是沒有對應的屬性名,只能經過指針和偏移量的方式訪問:

  • Java vtable:Java虛函數表,大小等於_vtable_len;
  • Java itables:Java接口函數表,大小等於 _itable_len;
  • 非靜態oop-map blocks ,大小等於_nonstatic_oop_map_size;
  • 接口的實現類,只有當前類表示一個接口時存在。若是接口沒有任何實現類則爲NULL;若是隻有一個實現類則爲該實現類的Klass指針;若是有多個實現類,爲當前類自己;
  • host klass,只在匿名類中存在,爲了支持JSR 292中的動態語言特性,會給匿名類生成一個host klass。 

HotSpot在解析一個類時會調用InstanceKlass::allocate_instance_klass()方法分配內存,而分配多大的內存則是經過調用InstanceKlass::size()計算出來的,調用語句以下: 

  int size = InstanceKlass::size(vtable_len,
								 itable_len,
								 nonstatic_oop_map_size,
		                         isinterf,
								 is_anonymous);

調用的size()方法的實現以下:

static int size(int vtable_length,
		          int itable_length,
                  int nonstatic_oop_map_size,
                  bool is_interface,
				  bool is_anonymous
  ){
    return align_object_size(header_size()    +  // header_size()爲55
           align_object_offset(vtable_length) +
           align_object_offset(itable_length) +
           (
                  (is_interface || is_anonymous) ?
                  align_object_offset(nonstatic_oop_map_size) :
                  nonstatic_oop_map_size
		   ) +
           (
        		   is_interface ? (int)sizeof(Klass*)/HeapWordSize : 0
           ) +
           (
        		   is_anonymous ? (int)sizeof(Klass*)/HeapWordSize : 0)
		   );
  }

能夠看到除了會爲類中自己的屬性分配內存,也會爲vtable與itable等分配內存。調用的header_size()方法就是計算此類的對象所佔用的內存大小,實現以下:

// Sizing (in words) 
static int header_size(){ 
  return align_object_offset(sizeof(InstanceKlass)/HeapWordSize); // 以HeapWordSize爲單位,64位一個字爲8字節,因此值爲8 
}

調用的align_object_offset()方法是進行內存對齊,這是一塊很是重要的C++知識點,後面會專門進行講解。 

三、InstanceKlass類的子類

InstanceKlass共有3個直接子類,這3個子類用來表示一些特殊的類,下面簡單介紹一下這3個子類:

(1)InstanceRefKlass

java/lang/ref/Reference的子類須要使用InstanceRefKlass類來表示,由於這些類須要垃圾回收器特殊處理 ,在後續講解強引用、弱引用、虛引用以及幽靈引用時在詳細介紹。

(2)InstanceMirrorKlass 

用於表示特殊的java.lang.Class類,咱們須要分清相關類的表示方法,以下圖所示。

java.lang.Class對象是經過對應的Oop對象來保存類的靜態屬性,所以他們的實例大小不一樣,須要特殊的方式來計算他們的大小以及屬性遍歷。

Klass的屬性_java_mirror就指向保存該類靜態字段的Oop對象,可經過該屬性訪問類的靜態字段。 Oop是HotSpot的對象表示模型,在後面會詳細介紹。

 (3)InstanceClassLoaderKlass 

沒有添加新的字段,增長了新的oop遍歷方法,主要用於類加載器依賴遍歷使用。  

建立InstanceKlass實例會調用InstanceKlass::allocate_instance_klass()方法。在建立時,會涉及到C++new運算符的重載,經過重載new運算符來分配對象的內存空間,也就是調用InstanceKlass::size()方法獲得的大小,而後再調用對應類的構造函數初始化相應的屬性。方法的實現以下:

InstanceKlass* InstanceKlass::allocate_instance_klass(
                                              ClassLoaderData* loader_data,
                                              int vtable_len,
                                              int itable_len,
                                              int static_field_size,
                                              int nonstatic_oop_map_size,
                                              ReferenceType rt,
                                              AccessFlags access_flags,
                                              Symbol* name,
                                              Klass* super_klass,
                                              bool is_anonymous,
                                              TRAPS) {
  bool isinterf = access_flags.is_interface();
  int size = InstanceKlass::size(vtable_len,
								 itable_len,
								 nonstatic_oop_map_size,
		                         isinterf,
								 is_anonymous);

  // Allocation
  InstanceKlass* ik;
  ///////////////////////////////////////////////////////////////////////
  if (rt == REF_NONE) {
    if (name == vmSymbols::java_lang_Class()) {
      ik = new (loader_data, size, THREAD) InstanceMirrorKlass(
                       vtable_len,
					   itable_len,
					   static_field_size,
					   nonstatic_oop_map_size,
					   rt,
                       access_flags, is_anonymous);
    } else if (
    	  name == vmSymbols::java_lang_ClassLoader() ||
          (
             SystemDictionary::ClassLoader_klass_loaded() &&
             super_klass != NULL &&
             super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass()) // ClassLoader_klass爲java_lang_ClassLoader
		  )
    ){
      ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(
                       vtable_len,
					   itable_len,
					   static_field_size,
					   nonstatic_oop_map_size,
					   rt,
                       access_flags, is_anonymous);
    } else {
      // normal class
      ik = new (loader_data, size, THREAD) InstanceKlass(
				vtable_len, itable_len,
				static_field_size,
				nonstatic_oop_map_size,
				rt,
				access_flags, is_anonymous);
    }
  }
  ///////////////////////////////////////////////////////////////////////
  else {
    // reference klass
    ik = new (loader_data, size, THREAD) InstanceRefKlass(
				vtable_len, itable_len,
				static_field_size,
				nonstatic_oop_map_size,
				rt,
				access_flags, is_anonymous);
  }
  ///////////////////////////////////////////////////////////////////////

  // 添加全部類型到咱們內部類加載器列表中,包括在根加載器中的類
  // Add all classes to our internal class loader list here,
  // including classes in the bootstrap (NULL) class loader.
  // loader_data的類型爲ClassLoaderData*,經過ClassLoaderData中的_klasses保持經過InstanceKlass._next_link屬性保持的列表
  loader_data->add_class(ik);

  return ik;
}

方法的實現比較簡單,當rt等於REF_NONE時,也就是爲非Reference類型時,會根據類名建立對應C++類的對象。Class類建立InstanceMirrorKlass、ClassLoader類或ClassLoader的子類建立InstanceClassLoaderKlass類、普通類經過InstanceKlass來表示。當rt不爲REF_NONE時,會建立InstanceRefKlass對象。REF_NONE枚舉常量的定義以下: 

// ReferenceType is used to distinguish between java/lang/ref/Reference subclasses

enum ReferenceType {
  REF_NONE,      // Regular class
  REF_OTHER,     // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below
  REF_SOFT,      // Subclass of java/lang/ref/SoftReference
  REF_WEAK,      // Subclass of java/lang/ref/WeakReference
  REF_FINAL,     // Subclass of java/lang/ref/FinalReference
  REF_PHANTOM    // Subclass of java/lang/ref/PhantomReference
};

能夠看到,全部的Reference及子類都會用InstanceRefKlass來表示。當沒法判斷究竟是哪一個子類時,會將Reference設置爲REF_OTHER。  

 

相關文章的連接以下:

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

二、調試HotSpot源代碼

三、HotSpot項目結構 

四、HotSpot的啓動過程 

五、HotSpot二分模型(1)

六、HotSpot的類模型(2)  

七、HotSpot的類模型(3) 

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

相關文章
相關標籤/搜索