核心类的预装载

查看hotspot/src/share/vm/memory/universe.cpp中的Universe::genesis()函数的实现,其中有对数组及核心类的加载逻辑。数组类没有对应的Class文件,所以在类装载阶段,数组类会被虚拟机直接创建,也不需要进行验证、准备和初始化等操作;类加载就是通过宏来定义一些需要加载的核心类,然后调用前面介绍的一些类加载器方法来加载类。数组类的创建如下:

_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);

数组类的创建在前面介绍类模型时介绍过,这里不再介绍。 

HotSpot在启动过程中会预先加载一些核心类,如Object、String等,如下: 

源代码位置:/src/share/vm/classfile/systemDictionary.hpp
#define WK_KLASSES_DO(do_klass)                               \
/* well-known classes */                                      \
do_klass(Object_klass,      java_lang_Object ,         Pre)   \
do_klass(String_klass,      java_lang_String,          Pre )  \
do_klass(Class_klass,       java_lang_Class,           Pre )  \
do_klass(Cloneable_klass,   java_lang_Cloneable,       Pre )  \
do_klass(ClassLoader_klass, java_lang_ClassLoader,     Pre )  \
do_klass(Serializable_klass, java_io_Serializable,     Pre)   \
do_klass(System_klass,       java_lang_System,         Pre )  \
...

如上通过宏定义了一些类及类的一些相关属性,这个宏在枚举类WKID中使用,如下:

enum WKID {
    NO_WKID = 0,
 
    #define WK_KLASS_ENUM(name, symbol, ignore_o) WK_KLASS_ENUM_NAME(name), WK_KLASS_ENUM_NAME(symbol) = WK_KLASS_ENUM_NAME(name),
    WK_KLASSES_DO(WK_KLASS_ENUM)
    #undef WK_KLASS_ENUM
 
    WKID_LIMIT,
    FIRST_WKID = NO_WKID + 1
};

经过宏扩展后,变为了如下的形式:

enum WKID {
  NO_WKID = 0,
 
  Object_klass_knum, java_lang_Object_knum = Object_klass_knum, \
  String_klass_knum, java_lang_String_knum = String_klass_knum, \
  Class_klass_knum, java_lang_Class_knum = Class_klass_knum,    \
  Cloneable_klass_knum, java_lang_Cloneable_knum = Cloneable_klass_knum,        \
  ClassLoader_klass_knum, java_lang_ClassLoader_knum = ClassLoader_klass_knum,  \
  Serializable_klass_knum, java_io_Serializable_knum = Serializable_klass_knum, \
  System_klass_knum, java_lang_System_knum = System_klass_knum,                 \
  ...
 
  WKID_LIMIT,                    // 70
  FIRST_WKID = NO_WKID + 1       // 1
};

这些类在HotSpot启动时就会进行预加载,调用链路如下:

Universe::genesis()                           universe.cpp
SystemDictionary::initialize()                     systemDictionary.cpp
SystemDictionary::initialize_preloaded_classes()   systemDictionary.cpp
SystemDictionary::initialize_wk_klasses_through()  systemDictionary.hpp
SystemDictionary::initialize_wk_klasses_until()    systemDictionary.cpp

SystemDictionary::initialize_preloaded_classes 是分批次预加载类的。首先会调用SystemDictionary::initialize_wk_klasses_until()函数,在这个函数中遍历WK_KLASSES_DO宏中定义的所有需要预加载的类,函数的具体实现如下:

void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id, TRAPS) {
  assert((int)start_id <= (int)limit_id, "IDs are out of order!");
  for (int id = (int)start_id; id < (int)limit_id; id++) {
    assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob");
    int info = wk_init_info[id - FIRST_WKID];
    int sid  = (info >> CEIL_LG_OPTION_LIMIT);
    // right_n_bits的宏扩展为((CEIL_LG_OPTION_LIMIT >= BitsPerWord ? 0 : OneBit << (CEIL_LG_OPTION_LIMIT)) - 1)
    int opt  = (info & right_n_bits(CEIL_LG_OPTION_LIMIT));
 
    initialize_wk_klass((WKID)id, opt, CHECK);
  }
  // move the starting value forward to the limit:
  start_id = limit_id;
}

其中wk_init_info数组的定义如下:

static const short wk_init_info[] = {
  #define WK_KLASS_INIT_INFO(name, symbol, option) \
    ( ((int)vmSymbols::VM_SYMBOL_ENUM_NAME(symbol) << SystemDictionary::CEIL_LG_OPTION_LIMIT) | (int)SystemDictionary::option ),
  WK_KLASSES_DO(WK_KLASS_INIT_INFO)
  #undef WK_KLASS_INIT_INFO
  0
};

最终的wk_init_info数组经过宏扩展后如下:

static const short wk_init_info[] = {
( ((int)vmSymbols::java_lang_Object_enum << SystemDictionary::CEIL_LG_OPTION_LIMIT)                      | (int)SystemDictionary::Pre ), \
( ((int)vmSymbols::java_lang_String_enum << SystemDictionary::CEIL_LG_OPTION_LIMIT)                      | (int)SystemDictionary::Pre ), \
( ((int)vmSymbols::java_lang_Class_enum  << SystemDictionary::CEIL_LG_OPTION_LIMIT)                      | (int)SystemDictionary::Pre ), \
( ((int)vmSymbols::java_lang_Cloneable_enum << SystemDictionary::CEIL_LG_OPTION_LIMIT)                   | (int)SystemDictionary::Pre ), \
( ((int)vmSymbols::java_lang_ClassLoader_enum  << SystemDictionary::CEIL_LG_OPTION_LIMIT)                | (int)SystemDictionary::Pre ), \
( ((int)vmSymbols::java_io_Serializable_enum  << SystemDictionary::CEIL_LG_OPTION_LIMIT)                 | (int)SystemDictionary::Pre ), \
( ((int)vmSymbols::java_lang_System_enum  << SystemDictionary::CEIL_LG_OPTION_LIMIT)                     | (int)SystemDictionary::Pre ), \
...
0
};

在SystemDictionary::initialize_wk_klasses_until()函数或如上wk_init_info数组中用到的CEIL_LG_OPTION_LIMIT是枚举变量,定义在InitOption枚举类中,如下:

enum InitOption {
    Pre,                        // preloaded; error if not present
    Pre_JSR292,                 // preloaded if EnableInvokeDynamic
 
    // Order is significant.  Options before this point require resolve_or_fail.
    // Options after this point will use resolve_or_null instead.
 
    Opt,                        // preload tried; NULL if not present
    Opt_Only_JDK14NewRef,       // preload tried; use only with NewReflection
    Opt_Only_JDK15,             // preload tried; use only with JDK1.5+
    OPTION_LIMIT,
    CEIL_LG_OPTION_LIMIT = 4  // OPTION_LIMIT <= (1< 
 

在initialize_wk_klasses_until()函数中调用的initialize_wk_klasses()函数的实现如下: 

bool SystemDictionary::initialize_wk_klass(WKID id, int init_opt, TRAPS) {
  assert(id >= (int)FIRST_WKID && id < (int)WKID_LIMIT, "oob");
  int  info = wk_init_info[id - FIRST_WKID];
  int  sid  = (info >> CEIL_LG_OPTION_LIMIT);
  Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid);
  Klass** klassp = &_well_known_klasses[id];
  bool must_load = (init_opt < SystemDictionary::Opt);
  if ((*klassp) == NULL) {
     if (must_load) {
        (*klassp) = resolve_or_fail(symbol, true, CHECK_0); // load required class
     } else {
        (*klassp) = resolve_or_null(symbol, CHECK_0); // load optional klass
     }
  }
  return ((*klassp) != NULL);
}

调用resolve_or_fail()或resolve_or_null()函数进行类的加载,由名称也可以区分出这两个方法的区别。resolve_or_fail()方法表示加载的类一定要成功加载,也就是在wk_init_info数组中标注有Pre与Pre_JSR292的类;resolve_or_null()方法表示加载的类如果有就加载,没有返回NULL即可。 

最终会调用到SystemDictionary::load_instance_class()函数,如在加载核心类时,调用链路如下:

SystemDictionary::resolve_or_fail()                   systemDictionary.cpp
SystemDictionary::resolve_or_fail()                   systemDictionary.cpp
SystemDictionary::resolve_or_null()                   systemDictionary.cpp
SystemDictionary::resolve_instance_class_or_null()    systemDictionary.cpp
SystemDictionary::load_instance_class()               systemDictionary.cpp

resolve_or_fail()方法的实现如下: 

Klass* SystemDictionary::resolve_or_fail(Symbol* class_name, Handle class_loader, Handle protection_domain, bool throw_error, TRAPS) {
  Klass* klass = resolve_or_null(class_name, class_loader, protection_domain, THREAD);
  if (HAS_PENDING_EXCEPTION || klass == NULL) { 
     KlassHandle k_h(THREAD, klass);
     // can return a null klass
     klass = handle_resolution_exception(class_name, class_loader, protection_domain, throw_error, k_h, THREAD);
  }
  return klass;
}

调用resolve_or_null()方法来加载类,不过klass一定不能为空,如果为空则出异常。调用的resolve_or_null()方法的实现如下:

Klass* SystemDictionary::resolve_or_null(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS) {
  // 数组,通过签名的格式来判断
  if (FieldType::is_array(class_name)) {
    return resolve_array_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  }
  // 普通类,通过签名的格式来判断
  else if (FieldType::is_obj(class_name)) {
    ResourceMark rm(THREAD);
    // Ignore wrapping L and ;.
    TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1,
                                                 class_name->utf8_length() - 2,
						 CHECK_NULL);
    return resolve_instance_class_or_null(name, class_loader, protection_domain, CHECK_NULL);
  }
  else {
    return resolve_instance_class_or_null(class_name, class_loader, protection_domain, CHECK_NULL);
  }
}

调用resolve_array_class_or_null()方法来加载数组,调用resolve_instance_class_or_null()方法加载类。数组类没有对应的Class文件,所以在类装载阶段,数组类会被虚拟机直接创建,并且数组类在装载完成后的状态为generated,即不需要进行验证、准备和初始化等操作。方法已经在前一篇介绍过,这里不再介绍。  

相关文章的链接如下:

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

2、调试HotSpot源代码

3、HotSpot项目结构 

4、HotSpot的启动过程 

5、HotSpot二分模型(1)

6、HotSpot的类模型(2)  

7、HotSpot的类模型(3) 

8、HotSpot的类模型(4)

9、HotSpot的对象模型(5)  

10、HotSpot的对象模型(6) 

11、操作句柄Handle(7)

12、句柄Handle的释放(8)

13、类加载器 

14、类的双亲委派机制 

作者持续维护的个人博客classloading.com

关注公众号,有HotSpot源码剖析系列文章!

  

  

 

你可能感兴趣的:(核心类的预装载)