类加载流程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数组的创建,其他几种的基本类型数组流程也是同样的.
在正式介绍之前,先介绍如下内容:
- jvm 内部中基本类型所对应的大小
- 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(); }
};
创建流程
-
调用如下代码创建 boolean类型的数组
_boolArrayKlassObj = typeArrayKlass::create_klass(T_BOOLEAN, sizeof(jboolean), CHECK);
这里注意的是,sizeof(jboolean) = sizeof(unsigned char)
-
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
-
执行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(); }
-
创建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);}
-
获得symbolOop. 其最终执行的是SymbolTable::lookup(utf8_buffer, length, CHECK_NULL); 这里有必要介绍一下SymbolTable.其类图如下:
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.其类图如下:
HashtableBucket其内部指向HashtableEntry,而HashtableEntry实际上是一个链表. 因此, SymbolTable的数据结构就是数组+链表.
-
接下来,通过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在链表的首部.
-
-
创建typeArrayKlassKlassObj所对应的KlassHandle. typeArrayKlassKlassObj在之前已经创建完必.代码如下:
KlassHandle klassklass (THREAD, Universe::typeArrayKlassKlassObj());
-
接下来就是创建klassOop,这点和之前的文章类加载流程-002 流程是一样的,最终创建的结果如下:
-
其他的基本类型数组和上文介绍的一样,不同的是分配的大小,数组的名称不同罢了. 之后保存到全局变量_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;