src/java.base/share/native/launcher/main.c
java
main函數返回了JLI_Launch
()函數,位於src/java.base/share/native/libjli/java.c
segmentfault
JavaMain()是Java主程序的native調用。 數組
在該方法裏會執行虛擬機的初始化,獲取Java程序主類及main方法,而後經過JNI調用main方法, 自此,整個JVM進程執行結束,最終退出。app
int JavaMain(void *_args) { JavaMainArgs *args = (JavaMainArgs *) _args; int argc = args->argc; char **argv = args->argv; int mode = args->mode; char *what = args->what; InvocationFunctions ifn = args->ifn; JavaVM *vm = 0; JNIEnv *env = 0; jclass mainClass = NULL; jclass appClass = NULL; // 實際啓動的應用程序類 jmethodID mainID; jobjectArray mainArgs; int ret = 0; jlong start, end; RegisterThread(); /* 初始化虛擬機 */ start = CounterGet(); if (!InitializeJVM(&vm, &env, &ifn)) { JLI_ReportErrorMessage(JVM_ERROR1); exit(1); } if (showSettings != NULL) { ShowSettings(env, showSettings); CHECK_EXCEPTION_LEAVE(1); } // 顯示已解決的模塊並繼續 if (showResolvedModules) { ShowResolvedModules(env); CHECK_EXCEPTION_LEAVE(1); } // 列出可觀察的模塊,而後退出 if (listModules) { ListModules(env); CHECK_EXCEPTION_LEAVE(1); LEAVE(); } // 描述一個模塊,而後退出 if (describeModule != NULL) { DescribeModule(env, describeModule); CHECK_EXCEPTION_LEAVE(1); LEAVE(); } if (printVersion || showVersion) { PrintJavaVersion(env, showVersion); CHECK_EXCEPTION_LEAVE(0); if (printVersion) { LEAVE(); } } // 模塊在啓動時已經過驗證,所以退出 if (validateModules) { LEAVE(); } /* 若是用戶未指定類名或JAR文件 */ if (printXUsage || printUsage || what == 0 || mode == LM_UNKNOWN) { PrintUsage(env, printXUsage); CHECK_EXCEPTION_LEAVE(1); LEAVE(); } FreeKnownVMs(); /* 最後一次可能的PrintUsage以後 */ if (JLI_IsTraceLauncher()) { end = CounterGet(); JLI_TraceLauncher("%ld micro seconds to InitializeJVM\n", (long) (jint) Counter2Micros(end - start)); } /* 在此階段,argc / argv具備應用程序的參數 */ if (JLI_IsTraceLauncher()) { int i; printf("%s is '%s'\n", launchModeNames[mode], what); printf("App's argc is %d\n", argc); for (i = 0; i < argc; i++) { printf(" argv[%2d] = '%s'\n", i, argv[i]); } } ret = 1; /* * 加載Java程序的main方法,若是沒找到則退出 * * 獲取應用程序的主類. 它還檢查main方法是否存在 * 請參見 bugid 5030265。已經從 manifest 中解析了 Main-Class 名稱,可是沒有爲UTF-8支持對其進行正確解析。 * 所以,此處的代碼將忽略先前提取的值,並使用預先存在的代碼從新提取該值。 * 這多是發佈週期權宜之計。 * 可是,還發如今環境中傳遞某些字符集在Windows的某些變體中具備「奇怪」的行爲。 * 所以,也許永遠都不該加強啓動器本地的清單解析代碼。 * Hence the code here ignores the value previously extracted and * uses the pre-existing code to reextract the value. This is * possibly an end of release cycle expedient. * Hence, maybe the manifest parsing code local to the * launcher should never be enhanced. * * 所以,將來的工做應: * 1) 更正本地解析代碼,並驗證Main-Class屬性是否已正確經過全部環境, * 2) 刪除經過環境維護 main_class 的方法(並刪除這些註釋). * * 此方法還能夠正確處理啓動可能具備或不具備Main-Class清單條目的現有JavaFX應用程序. */ mainClass = LoadMainClass(env, mode, what); CHECK_EXCEPTION_NULL_LEAVE(mainClass); /* * 獲取程序主類Class對象 * * 在某些狀況下,當啓動 須要幫助程序的 應用程序(例如,沒有main方法的JavaFX應用程序)時, * mainClass將不是應用程序本身的主類,而是幫助程序類。 * 爲了使UI中的內容保持一致,咱們須要跟蹤和報告應用程序主類。 */ appClass = GetApplicationClass(env); NULL_CHECK_RETURN_VALUE(appClass, -1); /* 構建平臺特定的參數數組(構建main方法的參數列表) */ mainArgs = CreateApplicationArgs(env, argv, argc); CHECK_EXCEPTION_NULL_LEAVE(mainArgs); if (dryRun) { ret = 0; LEAVE(); } /* * PostJVMInit 使用類名稱做爲用於GUI的應用程序名稱 * 例如, 在 OSX 上, 這會在菜單欄中爲SWT和JavaFX設置應用程序名稱. * 所以, 咱們將在此處傳遞實際的應用程序類而不是mainClass, 由於這多是啓動器或幫助程序類, 而不是應用程序類. */ PostJVMInit(env, appClass, vm); CHECK_EXCEPTION_LEAVE(1); /* * 獲取main方法ID * * LoadMainClass不只加載主類,還將確保主方法的簽名正確,這樣就不須要再進一步檢查了. * 這裏調用main方法,以便無關的Java堆棧不在應用程序stack trace中. */ mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); CHECK_EXCEPTION_NULL_LEAVE(mainID); /* 調用main方法. */ (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); /* * 若是main拋出異常,則啓動程序的退出碼(在沒有對System.exit的調用的狀況下)將爲非零。 */ ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; LEAVE(); }
該方法中調用的InitializeJVM
()方法
會執行一系列關於虛擬機的分配、掛載、初始化等工做,
且聽下回分解函數
本文由博客一文多發平臺 OpenWrite 發佈!