从本文开始讲述类加载过程,在这里先解释一下类加载的时机是什么?
此时可以分为2种情况:
类的主动引用指的是:
类的被动使用指的是:
但是,jvm在启动过程中会预先加载一些类,如 object之类的. 该链条如下:
-- main (java.c)
-- JavaMain (java.c)
-- InitializeJVM (java.c)
-- create_vm (thread.cpp)
-- init_globals (init.cpp)
-- universe2_init (universe.cpp)
-- genesis (universe.cpp)
-- initialize (systemDictionary.cpp)
-- initialize_preloaded_classes (systemDictionary.cpp)
-- initialize_wk_klasses_through (systemDictionary.cpp)
-- initialize_wk_klasses_until (systemDictionary.cpp)
-- initialize_wk_klass ( systemDictionary.cpp)
-- resolve_or_fail (systemDictionary.cpp)
--resolve_instance_class_or_null ( systemDictionary.cpp)
-- load_instance_class ( systemDictionary.cpp)
-- load_classfile ( classLoader.cpp)
-- parseClassFile ( ClassFileParser.cpp ) 此处就开始加载了...
那么本文从何处讲起呢? 先从Universe::genesis 该方法讲起.
Universe::genesis 方法如下:
void Universe::genesis(TRAPS) {
ResourceMark rm;
{ FlagSetting fs(_bootstrapping, true);
{ MutexLocker mc(Compile_lock);
// determine base vtable size; without that we cannot create the array klasses 决定
compute_base_vtable_size();
if (!UseSharedSpaces) {
_klassKlassObj = klassKlass::create_klass(CHECK);
..... 改处创建一系列的klass
} else {
FileMapInfo *mapinfo = FileMapInfo::current_info();
char* buffer = mapinfo->region_base(CompactingPermGenGen::md);
void** vtbl_list = (void**)buffer;
init_self_patching_vtbl_list(vtbl_list,
CompactingPermGenGen::vtbl_list_size);
}
}
vmSymbols::initialize(CHECK);
SystemDictionary::initialize(CHECK);
klassOop ok = SystemDictionary::Object_klass();
_the_null_string = StringTable::intern("null", CHECK);
_the_min_jint_string = StringTable::intern("-2147483648", CHECK);
if (UseSharedSpaces) {
// 此处不执行
} else {
// Set up shared interfaces array. (Do this before supers are set up.)
_the_array_interfaces_array->obj_at_put(0, SystemDictionary::Cloneable_klass());
_the_array_interfaces_array->obj_at_put(1, SystemDictionary::Serializable_klass());
// Set element klass for system obj array klass
objArrayKlass::cast(_systemObjArrayKlassObj)->set_element_klass(ok);
objArrayKlass::cast(_systemObjArrayKlassObj)->set_bottom_klass(ok);
// Set super class for the classes created above
Klass::cast(boolArrayKlassObj() )->initialize_supers(ok, CHECK);
// .... 省略其他代码
}
Klass::cast(boolArrayKlassObj() )->append_to_sibling_list();
Klass::cast(charArrayKlassObj() )->append_to_sibling_list();
Klass::cast(singleArrayKlassObj() )->append_to_sibling_list();
Klass::cast(doubleArrayKlassObj() )->append_to_sibling_list();
Klass::cast(byteArrayKlassObj() )->append_to_sibling_list();
Klass::cast(shortArrayKlassObj() )->append_to_sibling_list();
Klass::cast(intArrayKlassObj() )->append_to_sibling_list();
Klass::cast(longArrayKlassObj() )->append_to_sibling_list();
Klass::cast(constantPoolKlassObj() )->append_to_sibling_list();
Klass::cast(systemObjArrayKlassObj())->append_to_sibling_list();
} // end of core bootstrapping
_objectArrayKlassObj = instanceKlass::
cast(SystemDictionary::Object_klass())->array_klass(1, CHECK);
Klass::cast(_objectArrayKlassObj)->append_to_sibling_list();
// Compute is_jdk version flags.
// Only 1.3 or later has the java.lang.Shutdown class.
// Only 1.4 or later has the java.lang.CharSequence interface.
// Only 1.5 or later has the java.lang.management.MemoryUsage class.
if (JDK_Version::is_partially_initialized()) {
uint8_t jdk_version;
klassOop k = SystemDictionary::resolve_or_null(
vmSymbolHandles::java_lang_management_MemoryUsage(), THREAD);
CLEAR_PENDING_EXCEPTION; // ignore exceptions
if (k == NULL) {
k = SystemDictionary::resolve_or_null(
vmSymbolHandles::java_lang_CharSequence(), THREAD);
CLEAR_PENDING_EXCEPTION; // ignore exceptions
if (k == NULL) {
k = SystemDictionary::resolve_or_null(
vmSymbolHandles::java_lang_Shutdown(), THREAD);
CLEAR_PENDING_EXCEPTION; // ignore exceptions
if (k == NULL) {
jdk_version = 2;
} else {
jdk_version = 3;
}
} else {
jdk_version = 4;
}
} else {
jdk_version = 5;
}
JDK_Version::fully_initialize(jdk_version);
}
}
什么是vtable? 在上篇文章有所介绍,此处再次介绍一下:
虚方法是c++的一个概念,c++中实现多态,是通过virtual 关键字,其底层是通过虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。
但是,问题来了,在JVM中是不能使用virtual的,因此,将一个类中 非static,非final,非private的方法都看做是 虚方法. 并通过vtable的技术来实现.
回到正题,我们来看一看compute_base_vtable_size,方法的实现:
void Universe::compute_base_vtable_size() {
_base_vtable_size = ClassLoader::compute_Object_vtable();
}
注意,这里的_base_vtable_size 是 universe的全局变量,声明如下:
int Universe::_base_vtable_size = 0;
ok,接下来我们来看一下ClassLoader::compute_Object_vtable方法:
int ClassLoader::compute_Object_vtable() {
// hardwired for JDK1.2 -- would need to duplicate class file parsing
// code to determine actual value from file
// Would be value '11' if finals were in vtable
int JDK_1_2_Object_vtable_size = 5;
return JDK_1_2_Object_vtable_size * vtableEntry::size();
}
一句话来总结,其最终的返回值是 5 * vtableEntry::size().
那么5 是啥意思呢? 我们都知道, java中的顶层父类为object,按照vtable的定义,object中恰好定义了如下方法:
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
protected void finalize() throws Throwable { }
vtableEntry::size()方法如下:
static int size() {
return sizeof(vtableEntry) / sizeof(HeapWord);
}
由于vtableEntry定义了如下字段:
methodOop _method; // 该类型为 methodOopDesc*,在32位上为长度4
同理,HeapWord 定义如下:
class HeapWord {
friend class VMStructs;
private:
char* i;
#ifndef PRODUCT
public:
char* value() { return i; }
#endif
};
因此,sizeof(HeapWord)等于4
那么vtableEntry::size()返回的结果就是 4/4 = 1 (words)
那么ClassLoader::compute_Object_vtable()返回的结果就是 : 5 * 1 = 5 (words).
后续流程,下文分解