HotSpot的类模型(3)

上一篇 HotSpot的类模子(2) 先容了类模子的基础类Klass的主要属性及方式,这一篇先容一下InstanceKlass及InstanceKlass的子类。

2、InstanceKlass类

每个InstanceKlass工具示意一个详细的Java类(这里的Java类不包罗Java数组)。InstanceKlass类及主要属性的界说如下:

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.
  
  ...
}

主要属性的先容如下表所示。

字段名 作用
_annotations Annotations类型的指针,保留该类使用的所有注解
_array_klasses

数组元素为该类的数组Klass指针,例如ObjArrayKlass是工具数组且元素类型为Object,

那么示意Object类的InstanceKlass工具的_array_klasses就是指向ObjArrayKlass的指针

_array_name

以该类为数组元素的数组的名字,如”[Ljava/lang/Object;”

_constants ConstantPool类型的指针,用来保留类的常量池信息
_inner_classes 用一个jushort数组保留当前类的InnerClasses属性和EnclosingMethod属性
_nonstatic_field_size 非静态字段需要占用的内存巨细 ,以字为单元
_static_field_size 静态字段需要占用的内存巨细 ,以字为单元
_generic_signature_index

保留此类的Generic signature在常量池中的索引

_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,界说了如下常量值:

  • 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组成一个元组,

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++知识点,后面会专门举行解说。 

3、InstanceKlass类的子类

InstanceKlass共有3个直接子类,这3个子类用来示意一些特殊的类,下面简朴先容一下这3个子类:

(1)InstanceRefKlass

什么是DevOps?该如何正确的在企业内进行实践

java/lang/ref/Reference的子类需要使用InstanceRefKlass类来示意,由于这些类需要垃圾接纳器特殊处置 ,在后续解说强引用、弱引用、虚引用以及幽灵引用时在详细先容。

(2)InstanceMirrorKlass 

用于示意特殊的java.lang.Class类,我们需要分清相关类的示意方式,如下图所示。

HotSpot的类模型(3)

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。  

 

相关文章的链接如下:

1、在Ubuntu 16.04上编译OpenJDK8的源代码 

2、调试HotSpot源代码

3、HotSpot项目结构 

4、HotSpot的启动历程 

5、HotSpot二分模子 (1)

6、HotSpot的类模子(2)  

 

原创文章,作者:admin,如若转载,请注明出处:https://www.2lxm.com/archives/20605.html