HotSpot源码篇-执行main方法

一、预加载类

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方法
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容