
本文旨在记录近期研读Java源码的学习心得与疑难问题。由于个人理解水平有限文中内容可能存在疏漏恳请读者不吝指正。前言在前文《探秘Bootstrap ClassLoader》中我们知道在JVM初始化时最终由jdk\src\solaris\bin\java_md_common.c中函数FindBootStrapClass()调用动态链接库libjvm.so中的函数JVM_FindClassFromBootLoader()加载并创建sun.launcher.LauncherHelper对象在Bootstrap Loader完成其初始化后由LauncherHelper完成后续Java应用启动和执行。本文通过源码详细分析启动类LancherHelper的加载过程。启动类LancherHelper加载过程在JVM_FindClassFromBootLoader()函数中是通过SystemDictionary::resolve_or_null()完成LancherHelper 类自身的加载和实例化。hotspot\src\share\vm\classfile\systemDictionary.cpp中load_instance_class()函数。由于完成LancherHelper类是由BootstrapCloader完成加载的而BootstrapCloader并没有实际的类只是一段C语言的代码因此在加载时class loader是null。instanceKlassHandle SystemDictionary::load_instance_class(Symbol*class_name,Handle class_loader,TRAPS){instanceKlassHandle nhinstanceKlassHandle();// null Handleif(class_loader.is_null()){// Search the shared system dictionary for classes preloaded into the// shared spaces.instanceKlassHandle k;{#ifINCLUDE_CDSPerfTraceTimevmtimer(ClassLoader::perf_shared_classload_time());kload_shared_class(class_name,class_loader,THREAD);#endif}if(k.is_null()){// Use VM class loaderPerfTraceTimevmtimer(ClassLoader::perf_sys_classload_time());kClassLoader::load_classfile(class_name,CHECK_(nh));}// find_or_define_instance_class may return a different InstanceKlassif(!k.is_null()){kfind_or_define_instance_class(class_name,class_loader,k,CHECK_(nh));}returnk;}else{// 省略class对应的class loader不是null的部分代码对于bootstrap class不会走的这个分支}}由下述源码中可以看出LauncherHelper类自身的内容是由_first_entry读取。_first_entry是JVM初始化时完成复制的具体过程和源码参见章节参数初始化。_first_entry就是LazyClassPathEntry实例在创建JVM时参数初始化对其赋值为LazyClassPathEntry。hotspot\src\share\vm\classfile\classLoader.cpp的load_classfile()函数源码如下instanceKlassHandle ClassLoader::load_classfile(Symbol*h_name,TRAPS){ResourceMarkrm(THREAD);constchar*class_nameh_name-as_C_string();EventMarkm(loading class %s,class_name);ThreadProfilerMarktpm(ThreadProfilerMark::classLoaderRegion);stringStream st;// st.print() uses too much stack space while handling a StackOverflowError// st.print(%s.class, h_name-as_utf8());st.print_raw(h_name-as_utf8());st.print_raw(.class);constchar*file_namest.as_string();ClassLoaderExt::Contextcontext(class_name,file_name,THREAD);// Lookup stream for parsing .class fileClassFileStream*streamNULL;intclasspath_index0;ClassPathEntry*eNULL;instanceKlassHandle h;{PerfClassTraceTimevmtimer(perf_sys_class_lookup_time(),((JavaThread*)THREAD)-get_thread_stat()-perf_timers_addr(),PerfClassTraceTime::CLASS_LOAD);// _first_entry在JVM初始化时设置成sysclasspath下面的jar参见hotspot\src\share\vm\runtime\os.cpp中os::set_boot_path(char fileSep, char pathSep)函数代码其中包含rt.jar就是sun.launcher.LauncherHelper类在的jar// 由于采用lazy加载机制此时的_first_entry就是LazyClassPathEntrye_first_entry;while(e!NULL){streame-open_stream(file_name,CHECK_NULL);if(!context.check(stream,classpath_index)){returnh;// NULL}if(stream!NULL){break;}// 处理下一个jaree-next();classpath_index;}}if(stream!NULL){// class file found, parse itClassFileParserparser(stream);ClassLoaderData*loader_dataClassLoaderData::the_null_class_loader_data();Handle protection_domain;TempNewSymbol parsed_nameNULL;instanceKlassHandle resultparser.parseClassFile(h_name,loader_data,protection_domain,parsed_name,context.should_verify(classpath_index),THREAD);// 省略异常处理部分代码hcontext.record_result(classpath_index,e,result,THREAD);}else{// 省略部分代码}returnh;}hotspot\src\share\vm\classfile\classLoader.cpp中LazyClassPathEntry::open_stream()函数代码。ClassFileStream*LazyClassPathEntry::open_stream(constchar*name,TRAPS){if(_meta_index!NULL!_meta_index-may_contain(name)){returnNULL;}if(_has_error){returnNULL;}ClassPathEntry*cperesolve_entry(THREAD);if(cpeNULL){_has_errortrue;returnNULL;}else{returncpe-open_stream(name,THREAD);}}hotspot\src\share\vm\classfile\classLoader.cpp中LazyClassPathEntry::resolve_entry()函数代码。找到LancherHelper类所属的rt.jar并读取LancherHelper.class内容创建ClassPathEntry实例。ClassPathEntry*LazyClassPathEntry::resolve_entry(TRAPS){// 创建LazyClassPathEntry实例时_resolved_entry nullif(_resolved_entry!NULL){return(ClassPathEntry*)_resolved_entry;}ClassPathEntry*new_entryNULL;// 此时执行create_class_path_entry()函数时第三个参数lazy是false需要实时加载class文件new_entryClassLoader::create_class_path_entry(_path,_st,false,_throw_exception,CHECK_NULL);if(!_throw_exceptionnew_entryNULL){assert(!HAS_PENDING_EXCEPTION,must be);returnNULL;}{ThreadCritical tc;if(_resolved_entryNULL){_resolved_entrynew_entry;returnnew_entry;}}assert(_resolved_entry!NULL,bug in MT-safe resolution logic);delete new_entry;return(ClassPathEntry*)_resolved_entry;}hotspot\src\share\vm\classfile\classLoader.cpp中create_class_path_entry()函数。ClassPathEntry*ClassLoader::create_class_path_entry(constchar*path,conststructstat*st,bool lazy,bool throw_exception,TRAPS){JavaThread*threadJavaThread::current();// lazy是falseif(lazy){returnnewLazyClassPathEntry(path,st,throw_exception);}ClassPathEntry*new_entryNULL;if((st-st_modeS_IFREG)S_IFREG){// Regular file, should be a zip file// Canonicalized filenamecharcanonical_path[JVM_MAXPATHLEN];if(!get_canonical_path(path,canonical_path,JVM_MAXPATHLEN)){// 省略部分代码}char*error_msgNULL;jzfile*zip;{// enable call to C landThreadToNativeFromVMttn(thread);HandleMarkhm(thread);zip(*ZipOpen)(canonical_path,error_msg);}if(zip!NULLerror_msgNULL){new_entrynewClassPathZipEntry(zip,path);// 省略部分代码}else{// 省略异常处理代码}}else{// Directorynew_entrynewClassPathDirEntry(path);// 省略部分代码}returnnew_entry;}参数初始化