类加载流程004

之前的几篇文章介绍了一堆klass对象的创建,本文我们来介绍一下 基本数组的创建. 这个和之前介绍的创建有所不同.

涉及到创建基本类型数组的代码如下:

_boolArrayKlassObj      = typeArrayKlass::create_klass(T_BOOLEAN, sizeof(jboolean), CHECK);
_charArrayKlassObj      = typeArrayKlass::create_klass(T_CHAR,    sizeof(jchar),    CHECK);
_singleArrayKlassObj    = typeArrayKlass::create_klass(T_FLOAT,   sizeof(jfloat),   CHECK);
_doubleArrayKlassObj    = typeArrayKlass::create_klass(T_DOUBLE,  sizeof(jdouble),  CHECK);
_byteArrayKlassObj      = typeArrayKlass::create_klass(T_BYTE,    sizeof(jbyte),    CHECK);
_shortArrayKlassObj     = typeArrayKlass::create_klass(T_SHORT,   sizeof(jshort),   CHECK);
_intArrayKlassObj       = typeArrayKlass::create_klass(T_INT,     sizeof(jint),     CHECK);
_longArrayKlassObj      = typeArrayKlass::create_klass(T_LONG,    sizeof(jlong),    CHECK);

_typeArrayKlassObjs[T_BOOLEAN] = _boolArrayKlassObj;
_typeArrayKlassObjs[T_CHAR]    = _charArrayKlassObj;
_typeArrayKlassObjs[T_FLOAT]   = _singleArrayKlassObj;
_typeArrayKlassObjs[T_DOUBLE]  = _doubleArrayKlassObj;
_typeArrayKlassObjs[T_BYTE]    = _byteArrayKlassObj;
_typeArrayKlassObjs[T_SHORT]   = _shortArrayKlassObj;
_typeArrayKlassObjs[T_INT]     = _intArrayKlassObj;
_typeArrayKlassObjs[T_LONG]    = _longArrayKlassObj;

本文只介绍boolean数组的创建,其他几种的基本类型数组流程也是同样的.

在正式介绍之前,先介绍如下内容:

  1. jvm 内部中基本类型所对应的大小
  2. handle,oopHandle的定义

jvm 内部基本数据类型

在/hotspot/src/share/vm/prims/jni.h中,关于基本数据类型,有如下定义:

typedef unsigned char   jboolean;
typedef unsigned short  jchar;
typedef short           jshort;
typedef float           jfloat;
typedef double          jdouble;

typedef jint            jsize;

在/hotspot/src/cpu/x86/vm/jni_x86.h中,有如下定义:

typedef int jint;

#ifdef _LP64  // 如果是64位的话
typedef long jlong;
#else
typedef long long jlong; // 如果是32位的话
#endif

handle 家族的定义

handle的定义是在 hotspot/src/share/vm/runtime/handles.hpp

class Handle VALUE_OBJ_CLASS_SPEC {
 private:
  oop* _handle;

 protected:
  oop     obj() const                            { return _handle == NULL ? (oop)NULL : *_handle; }
  oop     non_null_obj() const                   { assert(_handle != NULL, "resolving NULL handle"); return *_handle; }

 public:
  // Constructors
  Handle()                                       { _handle = NULL; }
  Handle(oop obj);
#ifndef ASSERT
  Handle(Thread* thread, oop obj);
#else
  // Don't inline body with assert for current thread
  Handle(Thread* thread, oop obj);
#endif // ASSERT

  // General access
  oop     operator () () const                   { return obj(); }
  oop     operator -> () const                   { return non_null_obj(); }
  bool    operator == (oop o) const              { return obj() == o; }
  bool    operator == (const Handle& h) const          { return obj() == h.obj(); }

  // Null checks
  bool    is_null() const                        { return _handle == NULL; }
  bool    not_null() const                       { return _handle != NULL; }

  // Debugging
  void    print()                                { obj()->print(); }

  // Direct interface, use very sparingly.
  // Used by JavaCalls to quickly convert handles and to create handles static data structures.
  // Constructor takes a dummy argument to prevent unintentional type conversion in C++.
  Handle(oop *handle, bool dummy)                { _handle = handle; }

  // Raw handle access. Allows easy duplication of Handles. This can be very unsafe
  // since duplicates is only valid as long as original handle is alive.
  oop* raw_value()                               { return _handle; }
  static oop raw_resolve(oop *handle)            { return handle == NULL ? (oop)NULL : *handle; }
};

而 oophandle是通过宏定义来实现的,如下:

#define DEF_HANDLE(type, is_a)                   \
  class type##Handle;                            \
  class type##Handle: public Handle {            \
   protected:                                    \
    type##Oop    obj() const                     { return (type##Oop)Handle::obj(); } \
    type##Oop    non_null_obj() const            { return (type##Oop)Handle::non_null_obj(); } \
                                                 \
   public:                                       \
    /* Constructors */                           \
    type##Handle ()                              : Handle()                 {} \
    type##Handle (type##Oop obj) : Handle((oop)obj) {                         \
      assert(SharedSkipVerify || is_null() || ((oop)obj)->is_a(),             \
             "illegal type");                                                 \
    }                                                                         \
    type##Handle (Thread* thread, type##Oop obj) : Handle(thread, (oop)obj) { \
      assert(SharedSkipVerify || is_null() || ((oop)obj)->is_a(), "illegal type");  \
    }                                                                         \
    \
    /* Special constructor, use sparingly */ \
    type##Handle (type##Oop *handle, bool dummy) : Handle((oop*)handle, dummy) {} \
                                                 \
    /* Operators for ease of use */              \
    type##Oop    operator () () const            { return obj(); } \
    type##Oop    operator -> () const            { return non_null_obj(); } \
  };

// 定义oop家族的handle体系
DEF_HANDLE(instance         , is_instance         ) // 类实例handle
DEF_HANDLE(method           , is_method           ) // 方法实例handle
DEF_HANDLE(constMethod      , is_constMethod      ) // 方法字节码handle
DEF_HANDLE(methodData       , is_methodData       ) // 性能统计handle
DEF_HANDLE(array            , is_array            ) // 数组handle
DEF_HANDLE(constantPool     , is_constantPool     ) // 常量池handle
DEF_HANDLE(constantPoolCache, is_constantPoolCache) // 常量池缓存handle
DEF_HANDLE(objArray         , is_objArray         ) // 引用类型数组handle
DEF_HANDLE(typeArray        , is_typeArray        ) // 基本类型数组handle
DEF_HANDLE(symbol           , is_symbol           )

此处就拿symbolHandle来举例,其声明的内容如下:

  class symbolHandle;                            
  class symbolHandle: public Handle {            
   protected:                                    
    symbolOop    obj() const
    { return (symbolOop)Handle::obj(); } 
    
    symbolOop    non_null_obj() const             { return (symbolOop)Handle::non_null_obj(); } 
                                                 
   public:                                       
    /* Constructors */                           
    symbolHandle ()                              : Handle()                 {} 
    symbolHandle (symbolOop obj) : Handle((oop)obj) {                         
      assert(SharedSkipVerify || is_null() || ((oop)obj)-> is_symbol(),             
             "illegal type");                                                 
    } 
                                                                            
    symbolHandle (Thread* thread, symbolOop obj) : Handle(thread, (oop)obj) { 
      assert(SharedSkipVerify || is_null() || ((oop)obj)-> is_symbol(), "illegal type"); 
    }                                                                         
    
    /* Special constructor, use sparingly */ 
    symbolHandle (symbolOop *handle, bool dummy) : Handle((oop*)handle, dummy) {} 
                                                 
    /* Operators for ease of use */              
    symbolOop    operator () () const            { return obj(); } 
    symbolOop    operator -> () const            { return non_null_obj(); } 
  };

创建流程

  1. 调用如下代码创建 boolean类型的数组

    _boolArrayKlassObj      = typeArrayKlass::create_klass(T_BOOLEAN, sizeof(jboolean), CHECK);
    

    这里注意的是,sizeof(jboolean) = sizeof(unsigned char)

  2. typeArrayKlass::create_klass 的代码如下:

     static inline klassOop create_klass(BasicType type, int scale, TRAPS) {
     return create_klass(type, scale, external_name(type), CHECK_NULL); }
    

    其调用external_name 获得指定类型数组的内部表示.其代码如下:

        const char* typeArrayKlass::external_name(BasicType type) {
       switch (type) {
         case T_BOOLEAN: return "[Z";
         case T_CHAR:    return "[C";
         case T_FLOAT:   return "[F";
         case T_DOUBLE:  return "[D";
         case T_BYTE:    return "[B";
         case T_SHORT:   return "[S";
         case T_INT:     return "[I";
         case T_LONG:    return "[J";
         default: ShouldNotReachHere();
       }
       return NULL;
      }
    

    因此,对于当前状况,其返回的是 [Z

  3. 执行typeArrayKlass::create_klass(BasicType type, int scale,const char* name_str, TRAPS) 方法,代码如下:

    	klassOop typeArrayKlass::create_klass(BasicType type, int scale,
                                          const char* name_str, TRAPS) {
      typeArrayKlass o;
    
      symbolHandle sym(symbolOop(NULL));
      // bootstrapping: don't create sym if symbolKlass not created yet
      if (Universe::symbolKlassObj() != NULL && name_str != NULL) {
        sym = oopFactory::new_symbol_handle(name_str, CHECK_NULL);
      }
      KlassHandle klassklass (THREAD, Universe::typeArrayKlassKlassObj());
    
      arrayKlassHandle k = base_create_array_klass(o.vtbl_value(), header_size(), klassklass, CHECK_NULL);
      typeArrayKlass* ak = typeArrayKlass::cast(k());
      ak->set_name(sym());
      ak->set_layout_helper(array_layout_helper(type));
      assert(scale == (1 << ak->log2_element_size()), "scale must check out");
      assert(ak->oop_is_javaArray(), "sanity");
      assert(ak->oop_is_typeArray(), "sanity");
      ak->set_max_length(arrayOopDesc::max_array_length(type));
      assert(k()->size() > header_size(), "bad size");
    
      // Call complete_create_array_klass after all instance variables have been initialized.
      KlassHandle super (THREAD, k->super());
      complete_create_array_klass(k, super, CHECK_NULL);
    
      return k();
    } 
    
  4. 创建typeArrayKlass,symbolHandle.由于在创建基本类型数组前已创建了symbolKlassObj.因此会通过 oopFactory::new_symbol_handle(name_str, CHECK_NULL); 来创建Handle. 其最终执行的代码如下:

    	static symbolHandle    new_symbol_handle(const char* name, int length, TRAPS) {
      symbolOop sym = new_symbol(name, length, THREAD);
      return symbolHandle(THREAD, sym);}
    
    1. 获得symbolOop. 其最终执行的是SymbolTable::lookup(utf8_buffer, length, CHECK_NULL); 这里有必要介绍一下SymbolTable.其类图如下:

      1

      SymbolTable是在universe::universe_init中调用SymbolTable::create_table() 完成创建的.代码如下:

      SymbolTable* SymbolTable::_the_table = NULL;
      
      static void create_table() {
         assert(_the_table == NULL, "One symbol table allowed.");
         _the_table = new SymbolTable();  }
      

      此时会执行其构造函数:

       SymbolTable() : Hashtable(symbol_table_size, sizeof (HashtableEntry)) {} // symbol_table_size = 20011
      

      接下来执行Hashtable的构造函数

      Hashtable(int table_size, int entry_size) : BasicHashtable(table_size, entry_size), _seed(0)  { }
      

      执行BasicHashtable的构造函数

          inline BasicHashtable::BasicHashtable(int table_size, int entry_size) {
           // Called on startup, no locking needed
           // 1. 初始化table_size, entry_size
           initialize(table_size, entry_size, 0);
           // 2. 在c堆上创建维度为table_size的HashtableBucket的数组
           _buckets = NEW_C_HEAP_ARRAY(HashtableBucket, table_size);
           for (int index = 0; index < _table_size; index++) {
             _buckets[index].clear();}}
      

      这里需要注意的是,默认情况下创建的是长度为20011的HashtableBucket的数组…

      这里介绍一下HashtableBucket.其类图如下:

      3

      HashtableBucket其内部指向HashtableEntry,而HashtableEntry实际上是一个链表. 因此, SymbolTable的数据结构就是数组+链表.

    2. 接下来,通过SymbolTable::lookup(const char* name, int len, TRAPS) 获得对应的symbolOop.其代码如下:

      symbolOop SymbolTable::lookup(const char* name, int len, TRAPS) {
         // 1. 获得该字符所对应的hash
         unsigned int hashValue = hash_symbol(name, len);
         // 2. 获得对应的index
         int index = the_table()->hash_to_index(hashValue);
       
         // 3. 在bucket中找寻symbol
         symbolOop s = the_table()->lookup(index, name, len, hashValue);
       
         // Found 4. 如果找到了,则直接返回
         if (s != NULL) return s;
       
         // We assume that lookup() has been called already, that it failed,
         // and symbol was not found.  We create the symbol here.
         // 5. 创建一个新的符号
         symbolKlass* sk  = (symbolKlass*) Universe::symbolKlassObj()->klass_part();
         symbolOop s_oop = sk->allocate_symbol((u1*)name, len, CHECK_NULL);
         symbolHandle sym (THREAD, s_oop);
       
         // Allocation must be done before grabbing the SymbolTable_lock lock 6. 获得锁
         MutexLocker ml(SymbolTable_lock, THREAD);
         // Otherwise, add to symbol to table 7. 添加符号
         return the_table()->basic_add(sym, index, (u1*)name, len, hashValue, CHECK_NULL);}
      

      这里重点看下第3步和第7步.其中第三步为:

        // Lookup a symbol in a bucket. 在bucket中找寻symbol
       
       symbolOop SymbolTable::lookup(int index, const char* name,
                                     int len, unsigned int hash) {
         int count = 0;
          // 1.从对应的HashtableBucket开始查找
         for (HashtableEntry* e = bucket(index); e != NULL; e = e->next()) {
           count++;
           if (e->hash() == hash) {
             // 2. 如果找到对应的,则直接返回symbolOop
             symbolOop sym = symbolOop(e->literal());
             if (sym->equals(name, len)) {
               return sym;
             }
           }
         }
         // If the bucket size is too deep check if this hash code is insufficient.
         // 3.如果bucket 链太长,则检查是否需要rehash
         if (count >= BasicHashtable::rehash_count && !needs_rehashing()) {
           _needs_rehashing = check_rehash_table(count);
         }
         return NULL;	}
      

      添加的代码为:

      symbolOop SymbolTable::basic_add(symbolHandle sym, int index_arg, u1 *name, int len,
                                    unsigned int hashValue_arg, TRAPS) {
      // Cannot hit a safepoint in this function because the "this" pointer can move.
      No_Safepoint_Verifier nsv;
      
      assert(sym->equals((char*)name, len), "symbol must be properly initialized");
      
      // Check if the symbol table has been rehashed, if so, need to recalculate
      // the hash value and index.
      // 1. 检查符号表是否已经重hash过了,如果是的话,则需要重新计算hash 值和index
      unsigned int hashValue;
      int index;
      if (use_alternate_hashcode()) {
       hashValue = hash_symbol((const char*)name, len);
       index = hash_to_index(hashValue);
      } else {
       hashValue = hashValue_arg;
       index = index_arg;
      }
      
      // Since look-up was done lock-free, we need to check if another
      // thread beat us in the race to insert the symbol.
      // 2. 检查是否有其他线程在我们前面完成了操作
      symbolOop test = lookup(index, (char*)name, len, hashValue);
      if (test != NULL) {
       // A race occurred and another thread introduced the symbol, this one
       // will be dropped and collected.
       return test;
      }
      
      // 3. 添加
      HashtableEntry* entry = new_entry(hashValue, sym());
      add_entry(index, entry);
      return sym();}
      

      其中第三步首先获得sym所对应的symbolOop(对应的代码为sym(), symbolHandle 重载了() ). 然后执行Hashtable::new_entry 创建 HashtableEntry. 代码如下:

          HashtableEntry* Hashtable::new_entry(unsigned int hashValue, oop obj) {
           HashtableEntry* entry;
           entry = (HashtableEntry*)BasicHashtable::new_entry(hashValue);
           entry->set_literal(obj);   // clears literal string field
           HS_DTRACE_PROBE4(hs_private, hashtable__new_entry,
             this, hashValue, obj, entry);
           return entry;}
      

      这里实例化了HashtableEntry.并设置其hash值为hashValue,_literal 为Symboloop,然后调用BasicHashtable::add_entry 进行添加.代码如下:

       inline void BasicHashtable::add_entry(int index, BasicHashtableEntry* entry) {
           entry->set_next(bucket(index));
           _buckets[index].set_entry(entry);
           ++_number_of_entries;}
      

      注意,这里使用了链表的倒插法,其最终的结果是,后添加的HashtableEntry在链表的首部.

  5. 创建typeArrayKlassKlassObj所对应的KlassHandle. typeArrayKlassKlassObj在之前已经创建完必.代码如下:

     KlassHandle klassklass (THREAD, Universe::typeArrayKlassKlassObj());
    
  6. 接下来就是创建klassOop,这点和之前的文章类加载流程-002 流程是一样的,最终创建的结果如下:
    6

  7. 其他的基本类型数组和上文介绍的一样,不同的是分配的大小,数组的名称不同罢了. 之后保存到全局变量_typeArrayKlassObjs 中,代码如下:

    _typeArrayKlassObjs[T_BOOLEAN] = _boolArrayKlassObj;
    _typeArrayKlassObjs[T_CHAR]    = _charArrayKlassObj;
    _typeArrayKlassObjs[T_FLOAT]   = _singleArrayKlassObj;
    _typeArrayKlassObjs[T_DOUBLE]  = _doubleArrayKlassObj;
    _typeArrayKlassObjs[T_BYTE]    = _byteArrayKlassObj;
    _typeArrayKlassObjs[T_SHORT]   = _shortArrayKlassObj;
    _typeArrayKlassObjs[T_INT]     = _intArrayKlassObj;
    _typeArrayKlassObjs[T_LONG]    = _longArrayKlassObj;
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值