原创

核心类的预装载

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

源代码位置:hotspot/src/share/vm/memory/universe.cpp

void Universe::genesis(TRAPS) {
  ResourceMark rm;

  {
    {
      MutexLocker mc(Compile_lock);
      // determine base vtable size; without that we cannot create the array klasses
      compute_base_vtable_size();

      if (!UseSharedSpaces) {
        _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;

        // ...
      }
    }
    // ...
}

基本类型的一维数组的创建在前面介绍类模型时介绍过,这里不再介绍。有了基本类型的一维数组后,可以方便地创建出任何维度的基本类型数组。

对于引用类型数组,只要创建出表示引用类型的Klass对象,就可以根据Klass及ObjTypeKlass中的一些字段表示出引用类型数组,例如创建Object一维数组。在Universe::genesis()函数中同样有如下调用:

InstanceKlass* ik = InstanceKlass::cast(SystemDictionary::Object_klass());
_objectArrayKlassObj = ik->array_klass(1, 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<<CEIL_LG_OPTION_LIMIT)  ceil_lg_option_limit
  };

在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,即不需要进行验证、准备和初始化等操作。方法已经在前一篇介绍过,这里不再介绍。  

正文到此结束