一、预加载类
hotspot/src/share/vm/memory/universe.cpp
void universe2_init() {
......
Universe::genesis(CATCH);
}
void Universe::genesis(TRAPS) {
//首先是基本型的初始化
.....
//初始化符号表
vmSymbols::initialize(CHECK);
//初始化系统字典
SystemDictionary::initialize(CHECK);
}
- 执行Java程序时会创建一个JVM线程进行初始化相关的操作,其中就包括universe2_init
- vmSymbols包括了JVM的符号常量
- SystemDictionary包括了已经加载了的类
hotspot/src/share/vm/classfile/vmSymbols.cpp
//注意这里的 VM_SYMBOLS_DO 符号
#define VM_SYMBOL_BODY(name, string) string "\0"
static const char* vm_symbol_bodies = VM_SYMBOLS_DO(VM_SYMBOL_BODY, VM_ALIAS_IGNORE);
void vmSymbols::initialize(TRAPS) {
if (!UseSharedSpaces) {
//vm_symbol_bodies声明在上面
const char* string = &vm_symbol_bodies[0];
for (int index = (int)FIRST_SID; index < (int)SID_LIMIT; index++) {
//为Java类创建符号
Symbol* sym = SymbolTable::new_permanent_symbol(string, CHECK);
//存到符号数组中
_symbols[index] = sym;
string += strlen(string); // skip string body
//下一个
string += 1; // skip trailing null
}
//Java基本类型
_type_signatures[T_BYTE] = byte_signature();
.....
// no single signatures for T_OBJECT or T_ARRAY
}
}
hotspot/src/share/vm/classfile/vmSymbols.hpp
#define VM_SYMBOLS_DO(template, do_alias) \
/* commonly used class, package, module names */ \
template(java_base, JAVA_BASE_NAME) \
template(java_lang_System, "java/lang/System") \
template(java_lang_Object, "java/lang/Object") \
template(java_lang_Class, "java/lang/Class") \
template(java_lang_Package, "java/lang/Package") \
template(java_lang_Module, "java/lang/Module") \
......
- VM_SYMBOLS_DO是个宏定义,包含了jdk的一些基本类型符号
hotspot/src/share/vm/classfile/symbolTable.cpp
Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) {
unsigned int hash;
//从符号表中查找符号应用,SymbolTable是HashTable
Symbol* result = SymbolTable::lookup_only((char*)name, (int)strlen(name), hash);
if (result != NULL) {
return result;
}
//如果不存在则创建hash索引,并放到表中
SymbolTable* table = the_table();
int index = table->hash_to_index(hash);
return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD);
}
- SymbolTable是个符号表,维护着Java类/字符等信息
- 首先查找是否存在该符号,如果没有则创建并添加到的SymbolTable
hotspot/src/share/vm/classfile/systemDictionary.cpp
void SystemDictionary::initialize(TRAPS) {
// Allocate arrays
_dictionary = new Dictionary(calculate_systemdictionary_size(PredictedLoadedClassCount));
_placeholders = new PlaceholderTable(_nof_buckets);
_number_of_modifications = 0;
_loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
_resolution_errors = new ResolutionErrorTable(_resolution_error_size);
_invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
// Allocate private object used as system class loader lock
_system_loader_lock_obj = oopFactory::new_intArray(0, CHECK);
// Initialize basic classes
initialize_preloaded_classes(CHECK);
}
- 系统字典初始化,系统字典维护者HotSpot对象模型的Klass,initialize_preloaded_classes执行预加载,主要是javabase模块下的类
hotspot/src/share/vm/classfile/systemDictionary.cpp
void SystemDictionary::initialize_preloaded_classes(TRAPS) {
//为Javabase模块创建ModuleEntry
ClassLoader::classLoader_init2(CHECK);
// 预加载类
WKID scan = FIRST_WKID;
....
//类加载
// JSR 292 classes
WKID jsr292_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
WKID jsr292_group_end = WK_KLASS_ENUM_NAME(VolatileCallSite_klass);
initialize_wk_klasses_until(jsr292_group_start, scan, CHECK);
initialize_wk_klasses_through(jsr292_group_end, scan, CHECK);
//其他类加载
//Java基本类型int等
....
}
void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id, TRAPS) {
for (int id = (int)start_id; id < (int)limit_id; id++) {
//
initialize_wk_klass((WKID)id, opt, CHECK);
}
}
bool SystemDictionary::initialize_wk_klass(WKID id, int init_opt, TRAPS) {
//查符号表
Symbol* symbol = vmSymbols::symbol_at((vmSymbols::SID)sid);
InstanceKlass** klassp = &_well_known_klasses[id];
k = resolve_or_fail(symbol, true, CHECK_0); // load required class
return ((*klassp) != NULL);
}
Klass* SystemDictionary::resolve_or_fail(Symbol* class_name, bool throw_error, TRAPS)
{
return resolve_or_fail(class_name, Handle(), Handle(), throw_error, THREAD);
}
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);
......
return klass;
}
Klass* SystemDictionary::resolve_or_null(Symbol* class_name, ...) {
//走了这里
return resolve_instance_class_or_null(class_name, class_loader, protection_domain, THREAD);
}
Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, ...) {
// Do actual loading
k = load_instance_class(name, class_loader, THREAD);
}
instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
if (k.is_null()) {
// Use VM class loader
PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time());
k = ClassLoader::load_classfile(class_name, CHECK_(nh));
}
}
- 预加载类,包括符号表中定义的类,javabase模块下的类,java基本类型等
- 最终调用ClassLoader::load_classfile方法对类进行加载
hotspot/src/share/vm/classfile/classLoader.cpp
instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
..............
if (stream != NULL) {
// class file found, parse it
ClassFileParser parser(stream);
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain;
TempNewSymbol parsed_name = NULL;
instanceKlassHandle result = parser.parseClassFile(h_name,
loader_data,
protection_domain,
parsed_name,
context.should_verify(classpath_index),
THREAD);
...........
} else {
.........
}
..........
}
- 创建字节码文件流,每个被加载的Java类都对应着一个ClassLoaderData结构,ClassLoaderData内部通过链表维护着ClassLoader和ClassLoader加载的类
- 调用parser.parseClassFile方法解析class文件
二、应用类加载
jdk/src/share/bin/java.c
int JNICALL
JavaMain(void * _args)
{
........
// 虚拟机启动成功
if (!InitializeJVM(&vm, &env, &ifn)) {
JLI_ReportErrorMessage(JVM_ERROR1);
exit(1);
}
......
// 加载主类
mainClass = LoadMainClass(env, mode, what);
.....
// 获取主类的main方法
mainID = (*env)->GetStaticMethodID(env, mainClass, "main",
"([Ljava/lang/String;)V");
....
// 调用main方法
(*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs);
.....
}
- 在HotSpot启动以后,加载主类
- 获取主类的main方法,最后执行main方法
jdk/src/share/bin/java.c
static jclass LoadMainClass(JNIEnv *env, int mode, char *name){
//LancherHelper类
jclass cls = GetLauncherHelperClass(env);
//获取LancherHelper类的checkAndLoadMain方法
NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,"checkAndLoadMain",
"(ZILjava/lang/String;)Ljava/lang/Class;"));
NULL_CHECK0(str = NewPlatformString(env, name));
//使用checkAndLoadMain加载主类
NULL_CHECK0(result = (*env)->CallStaticObjectMethod(env, cls, mid,USE_STDERR, mode, str));
return (jclass)result;
}
jclass
GetLauncherHelperClass(JNIEnv *env)
{
if (helperClass == NULL) {
NULL_CHECK0(helperClass = FindBootStrapClass(env,
"sun/launcher/LauncherHelper"));
}
return helperClass;
}
- 在加载主类之前先加载LancherHelper类
- 获取LancherHelper的checkAndLoadMain方法
- checkAndLoadMain方法会去加载主类
- GetLauncherHelperClass方法会去加载jdk的LauncherHelper类
jdk/src/java.base/unix/native/libjli/java_md_common.c
jclass FindBootStrapClass(JNIEnv *env, const char* classname)
{
if (findBootClass == NULL) {
//获取jvm.cpp中的JVM_FindClassFromBootLoader方法
findBootClass = (FindClassFromBootLoader_t *)dlsym(RTLD_DEFAULT,
"JVM_FindClassFromBootLoader");
........
}
return findBootClass(env, classname); //调用JVM_FindClassFromBootLoader方法
}
- 利用dlsym调用JVM_FindClassFromBootLoader方法,加载类
hotspot/src/share/vm/prims/jvm.cpp
调用SystemDictionary解析类去加载类,流程与内部预加载类的加载机制一致
JVM_ENTRY(jclass, JVM_FindClassFromBootLoader(JNIEnv* env,
const char* name))
......
//调用SystemDictionary解析类去加载类,流程与内部预加载类的加载机制一致
Klass* k = SystemDictionary::resolve_or_null(h_name, CHECK_NULL);
return (jclass) JNIHandles::make_local(env, k->java_mirror());
JVM_END
- JVM_ENTRY是宏定义
- 执行 SystemDictionary::resolve_or_null对类进行加载
三、加载应用类
jdk/src/share/classes/sun/launcher/LauncherHelper.java
public static Class<?> checkAndLoadMain(boolean printToStderr,
int mode,
String what) {
initOutput(printToStderr);
// get the class name
String cn = null;
// mode为1,所以cn表示的就是主类
switch (mode) {
case LM_CLASS:
cn = what;
break;
case LM_JAR:
cn = getMainClassFromJar(what);
break;
default:
// should never happen
throw new InternalError("" + mode + ": Unknown launch mode");
}
cn = cn.replace('/', '.');
Class<?> mainClass = null;
try {
// scloader是系统类加载器,在创建对象的时候就已经初始化了
mainClass = scloader.loadClass(cn);
} catch (NoClassDefFoundError | ClassNotFoundException cnfe) {
if (System.getProperty("os.name", "").contains("OS X")
&& Normalizer.isNormalized(cn, Normalizer.Form.NFD)) {
try {
// On Mac OS X since all names with diacretic symbols are given as decomposed it
// is possible that main class name comes incorrectly from the command line
// and we have to re-compose it
mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC));
} catch (NoClassDefFoundError | ClassNotFoundException cnfe1) {
abort(cnfe, "java.launcher.cls.error1", cn);
}
} else {
abort(cnfe, "java.launcher.cls.error1", cn);
}
}
// set to mainClass
appClass = mainClass;
/*
* Check if FXHelper can launch it using the FX launcher. In an FX app,
* the main class may or may not have a main method, so do this before
* validating the main class.
*/
if (mainClass.equals(FXHelper.class) ||
FXHelper.doesExtendFXApplication(mainClass)) {
// Will abort() if there are problems with the FX runtime
FXHelper.setFXLaunchParameters(what, mode);
return FXHelper.class;
}
validateMainClass(mainClass);
return mainClass;
}
- 使用类加载器加载主类,mode=1,what为主类名
- scloader是系统类加载器,在创建LauncherHelper对象时就已经初始化
四、总结
- JVM启动的时候会对预加载类进行加载
- 用已经加载的LauncherHelper去加载主类,获取主类的main方法,最后调用主类的main方法