JVM源码分析:深入剖析java.c文件中JavaMain方法中InitializeJVM的实现
阅读原文时间:2023年08月16日阅读:1

经过前文《从JDK源码级深入剖析main方法的运行机制》的分析,我们知道了实现JavaMain方法的四个主要步骤:

  1. 初始化Java虚拟机

  2. 加载主运行类

  3. 通过加载的主运行类,获取main方法

  4. 调用main函数

下面,我们首先来看一下初始化Java虚拟机的具体实现细节。

上代码:

static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn){    JavaVMInitArgs args;    jint r;   //使用memset函数将args变量的所有字节都设置为0    memset(&args, 0, sizeof(args));    args.version  = JNI_VERSION_1_2;    args.nOptions = numOptions;    args.options  = options;    args.ignoreUnrecognized = JNI_FALSE;   //如果启用了跟踪启动器,则打印JavaVM参数信息    if (JLI_IsTraceLauncher()) {        int i = 0;        printf("JavaVM args:\n    ");        printf("version 0x%08lx, ", (long)args.version);        printf("ignoreUnrecognized is %s, ",               args.ignoreUnrecognized ? "JNI_TRUE" : "JNI_FALSE");        printf("nOptions is %ld\n", (long)args.nOptions);        for (i = 0; i < numOptions; i++)            printf("    option[%2d] = '%s'\n",                   i, args.options[i].optionString);    }   //创建Java虚拟机,CreateJavaVM由LoadJavaVM初始化    r = ifn->CreateJavaVM(pvm, (void **)penv, &args);     JLI_MemFree(options);    return r == JNI_OK;}

我们来到src\java.base\windows\native\libjli\java_md.c文件中的LoadJavaVM方法实现:

jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn){    HINSTANCE handle;    JLI_TraceLauncher("JVM path is %s\n", jvmpath);    /*LoadMSVCRT()函数是用来加载MSVCRT库的。MSVCRT是Microsoft Visual C++ Runtime Library的缩写,它是在Windows操作系统中提供C/C++运行时库的标准库。这个库包含了许多常用的函数,如字符串处理、数学计算、文件操作等。通过加载这个库,程序可以使用这些函数,从而简化代码的编写。     */    LoadMSVCRT();    /* 加载JVM的DLL文件*/      if ((handle = LoadLibrary(jvmpath)) == 0) {        JLI_ReportErrorMessage(DLL_ERROR4, (char *)jvmpath);        return JNI_FALSE;    }    /* 获取JNI_CreateJavaVM方法地址*/    ifn->CreateJavaVM =        (void *)GetProcAddress(handle, "JNI_CreateJavaVM");  //    /* 获取JVM默认的初始化参数*/    ifn->GetDefaultJavaVMInitArgs =        (void *)GetProcAddress(handle, "JNI_GetDefaultJavaVMInitArgs");    if (ifn->CreateJavaVM == 0 || ifn->GetDefaultJavaVMInitArgs == 0) {        JLI_ReportErrorMessage(JNI_ERROR1, (char *)jvmpath);        return JNI_FALSE;    }    return JNI_TRUE;}

在src\hotspot\share\prims\jni.cpp中,我们找到了JNI_CreateJavaVM方法的具体实现:

_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) {  jint result = JNI_ERR;  // On Windows, let CreateJavaVM run with SEH protection#if defined(_WIN32) && !defined(USE_VECTORED_EXCEPTION_HANDLING)  __try {#endif    //创建Java虚拟机的内部实现方法    result = JNI_CreateJavaVM_inner(vm, penv, args); #if defined(_WIN32) && !defined(USE_VECTORED_EXCEPTION_HANDLING)  } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) {    // Nothing to do.  }#endif  return result;}

继续找到JNI_CreateJavaVM_inner方法的实现,我们终于找到了创建Java虚拟机的代码实现:

static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { //下面这些代码是设置创建Java虚拟机相关方法的函数指针  HOTSPOT_JNI_CREATEJAVAVM_ENTRY((void **) vm, penv, args);  jint result = JNI_ERR;  DT_RETURN_MARK(CreateJavaVM, jint, (const jint&)result); ... //以下两个if代码是确保只有一个线程可以创建Java虚拟机  if (Atomic::xchg(&vm_created, IN_PROGRESS) != NOT_CREATED) {    return JNI_EEXIST;   // already created, or create attempt in progress  }  if (Atomic::xchg(&safe_to_recreate_vm, 0) == 0) {    return JNI_ERR;  }  ... //创建Java虚拟机具体实现  result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again);  //以下代码是将当前线程的Java虚拟机环境与主虚拟机环境绑定,并将创建完成的信息标记为已完成  JavaThread *thread = JavaThread::current();  assert(!thread->has_pending_exception(), "should have returned not OK");  *vm = (JavaVM *)(&main_vm);  *(JNIEnv**)penv = thread->jni_environment();  Atomic::release_store(&vm_created, COMPLETE);  ...   return result;}

以上,通过方法的层层调用,我们找到了创建Java虚拟机具体实现的方法Threads::create_vm((JavaVMInitArgs*) args, &can_try_again),由于里面内容太多,我们放到下一节再细讲。