OpenJDK源码赏析之三:Java命令参数的读取处理流程
承接上一篇
OpenJDK源碼賞析之二:java虛擬機(jī)啟動(dòng)流程到首函數(shù)調(diào)用全流程_星空_AZ的博客-CSDN博客
這篇這要解析Java虛擬機(jī)創(chuàng)建時(shí)候配置讀取時(shí)候命令行參數(shù)的讀取過程,這次采取逆向思維分析,從結(jié)尾順藤摸瓜找到源頭的方式去找到讀取命令行參數(shù)的地方,就從下面這個(gè)InitializeJVM函數(shù)為缺口慢慢展開全流程:
/** Initializes the Java Virtual Machine. Also frees options array when* finished.*/ static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) {JavaVMInitArgs args;jint r;memset(&args, 0, sizeof(args));args.version = JNI_VERSION_1_2;args.nOptions = numOptions;args.options = options;args.ignoreUnrecognized = JNI_FALSE;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);}r = ifn->CreateJavaVM(pvm, (void **)penv, &args);JLI_MemFree(options);return r == JNI_OK; }?注意到這一函數(shù)開始的注釋為初始化java虛擬機(jī),并釋放列表清單
最后? ? r = ifn->CreateJavaVM(pvm, (void **)penv, &args);這句為創(chuàng)建虛擬機(jī)
后面這句JLI_MemFree(options);就是釋放options的內(nèi)存空間了
那么既然找到釋放的地方,那也會(huì)有個(gè)創(chuàng)建的地方
搜索在java.c找到開頭有個(gè)地方定義了這個(gè)options
為JavaVMOption的結(jié)構(gòu)體,順著找,在jni.h找到該結(jié)構(gòu)體的定義位置
?optionString為設(shè)置字段,extraInfo為額外信息
在java.c查找到對(duì)JavaVMOption操作的地方,AddOption為在原來的基礎(chǔ)上添加設(shè)置,下面為其源碼:
/** Adds a new VM option with the given given name and value.*/ void AddOption(char *str, void *info) {/** Expand options array if needed to accommodate at least one more* VM option.*/if (numOptions >= maxOptions) {if (options == 0) {maxOptions = 4;options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));} else {JavaVMOption *tmp;maxOptions *= 2;tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));memcpy(tmp, options, numOptions * sizeof(JavaVMOption));JLI_MemFree(options);options = tmp;}}options[numOptions].optionString = str;options[numOptions++].extraInfo = info;if (JLI_StrCCmp(str, "-Xss") == 0) {jlong tmp;if (parse_size(str + 4, &tmp)) {threadStackSize = tmp;}}if (JLI_StrCCmp(str, "-Xmx") == 0) {jlong tmp;if (parse_size(str + 4, &tmp)) {maxHeapSize = tmp;}}if (JLI_StrCCmp(str, "-Xms") == 0) {jlong tmp;if (parse_size(str + 4, &tmp)) {initialHeapSize = tmp;}} }該函式為動(dòng)態(tài)擴(kuò)容函數(shù),一旦要讀取的命令行參數(shù)數(shù)量超過max自動(dòng)擴(kuò)容,非常值得分析
?這個(gè)部分的擴(kuò)容部分非常值得分析,我加了注釋的解析如下:
/** Expand options array if needed to accommodate at least one more* VM option.* 人工翻譯:如果需要至少容納一個(gè)或多個(gè)參數(shù),會(huì)展開選項(xiàng)容納空間*///當(dāng)選項(xiàng)數(shù)大于最大空間時(shí)if (numOptions >= maxOptions) {//如果沒有設(shè)置options,那么將最大設(shè)置變?yōu)?,然后分配空間if (options == 0) {maxOptions = 4;options = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));} else {//如果設(shè)置了options,將maxOptions擴(kuò)容為原來的二倍JavaVMOption *tmp;maxOptions *= 2;//先拿中間變量存儲(chǔ)分配新大小的一個(gè)空間,tmp = JLI_MemAlloc(maxOptions * sizeof(JavaVMOption));//用原來的options內(nèi)容復(fù)制到tmp中間變量中/*memcpy(tmp, options, numOptions * sizeof(JavaVMOption))將numOptions個(gè) */JavaVMOption存儲(chǔ)空間的options拷貝到tmp,從而完成對(duì)numOptions的賦值memcpy(tmp, options, numOptions * sizeof(JavaVMOption));//將原來的空間釋放掉JLI_MemFree(options);//將保存過的舊的數(shù)據(jù)放入新空間中options = tmp;}}插入:
注意memcpy,C 庫函數(shù)?void *memcpy(void *str1, const void *str2, size_t n)?從存儲(chǔ)區(qū)?str2?復(fù)制?n?個(gè)字節(jié)到存儲(chǔ)區(qū)?str1,這是個(gè)不安全的函數(shù),使用時(shí)候一定要多加注意
具體可看我的另外一篇文章:
memcpy函數(shù)及其缺陷分析_星空_AZ的博客-CSDN博客
回到正題:
那么接著去查找調(diào)用AddOption的地方,看看配置是從哪里進(jìn),就在上面的ParseArguments,命令參數(shù)語法分析函數(shù),以下為其源碼
static jboolean ParseArguments(int *pargc, char ***pargv,int *pmode, char **pwhat,int *pret, const char *jrepath) {int argc = *pargc;char **argv = *pargv;edint mode = LM_UNKNOWN;char *arg;*pret = 0;while ((arg = *argv) != 0 && *arg == '-') {argv++; --argc;if (JLI_StrCmp(arg, "-classpath") == 0 || JLI_StrCmp(arg, "-cp") == 0) {ARG_CHECK (argc, ARG_ERROR1, arg);SetClassPath(*argv);mode = LM_CLASS;argv++; --argc;} else if (JLI_StrCmp(arg, "-jar") == 0) {ARG_CHECK (argc, ARG_ERROR2, arg);mode = LM_JAR;} else if (JLI_StrCmp(arg, "-help") == 0 ||JLI_StrCmp(arg, "-h") == 0 ||JLI_StrCmp(arg, "-?") == 0) {printUsage = JNI_TRUE;return JNI_TRUE;} else if (JLI_StrCmp(arg, "-version") == 0) {printVersion = JNI_TRUE;return JNI_TRUE;} else if (JLI_StrCmp(arg, "-showversion") == 0) {showVersion = JNI_TRUE;} else if (JLI_StrCmp(arg, "-X") == 0) {printXUsage = JNI_TRUE;return JNI_TRUE; /** The following case checks for -XshowSettings OR -XshowSetting:SUBOPT.* In the latter case, any SUBOPT value not recognized will default to "all"*/} else if (JLI_StrCmp(arg, "-XshowSettings") == 0 ||JLI_StrCCmp(arg, "-XshowSettings:") == 0) {showSettings = arg;} else if (JLI_StrCmp(arg, "-Xdiag") == 0) {AddOption("-Dsun.java.launcher.diag=true", NULL); /** The following case provide backward compatibility with old-style* command line options.*/} else if (JLI_StrCmp(arg, "-fullversion") == 0) {JLI_ReportMessage("%s full version \"%s\"", _launcher_name, GetFullVersion());return JNI_FALSE;} else if (JLI_StrCmp(arg, "-verbosegc") == 0) {AddOption("-verbose:gc", NULL);} else if (JLI_StrCmp(arg, "-t") == 0) {AddOption("-Xt", NULL);} else if (JLI_StrCmp(arg, "-tm") == 0) {AddOption("-Xtm", NULL);} else if (JLI_StrCmp(arg, "-debug") == 0) {AddOption("-Xdebug", NULL);} else if (JLI_StrCmp(arg, "-noclassgc") == 0) {AddOption("-Xnoclassgc", NULL);} else if (JLI_StrCmp(arg, "-Xfuture") == 0) {AddOption("-Xverify:all", NULL);} else if (JLI_StrCmp(arg, "-verify") == 0) {AddOption("-Xverify:all", NULL);} else if (JLI_StrCmp(arg, "-verifyremote") == 0) {AddOption("-Xverify:remote", NULL);} else if (JLI_StrCmp(arg, "-noverify") == 0) {AddOption("-Xverify:none", NULL);} else if (JLI_StrCCmp(arg, "-prof") == 0) {char *p = arg + 5;char *tmp = JLI_MemAlloc(JLI_StrLen(arg) + 50);if (*p) {sprintf(tmp, "-Xrunhprof:cpu=old,file=%s", p + 1);} else {sprintf(tmp, "-Xrunhprof:cpu=old,file=java.prof");}AddOption(tmp, NULL);} else if (JLI_StrCCmp(arg, "-ss") == 0 ||JLI_StrCCmp(arg, "-oss") == 0 ||JLI_StrCCmp(arg, "-ms") == 0 ||JLI_StrCCmp(arg, "-mx") == 0) {char *tmp = JLI_MemAlloc(JLI_StrLen(arg) + 6);sprintf(tmp, "-X%s", arg + 1); /* skip '-' */AddOption(tmp, NULL);} else if (JLI_StrCmp(arg, "-checksource") == 0 ||JLI_StrCmp(arg, "-cs") == 0 ||JLI_StrCmp(arg, "-noasyncgc") == 0) {/* No longer supported */JLI_ReportErrorMessage(ARG_WARN, arg);} else if (JLI_StrCCmp(arg, "-version:") == 0 ||JLI_StrCmp(arg, "-no-jre-restrict-search") == 0 ||JLI_StrCmp(arg, "-jre-restrict-search") == 0 ||JLI_StrCCmp(arg, "-splash:") == 0) {; /* Ignore machine independent options already handled */} else if (ProcessPlatformOption(arg)) {; /* Processing of platform dependent options */} else if (RemovableOption(arg)) {; /* Do not pass option to vm. */} else {AddOption(arg, NULL);}}if (--argc >= 0) {*pwhat = *argv++;}if (*pwhat == NULL) {*pret = 1;} else if (mode == LM_UNKNOWN) {/* default to LM_CLASS if -jar and -cp option are* not specified */mode = LM_CLASS;}if (argc >= 0) {*pargc = argc;*pargv = argv;}*pmode = mode;return JNI_TRUE; }哈哈,看到平常在命令行輸入的-help參數(shù)沒有
?就是在這里讀取的,讀取了在cmd輸入的命令行參數(shù),具體還有很多細(xì)節(jié),沒分析到位,水平有限諒解一下哈
總結(jié)
以上是生活随笔為你收集整理的OpenJDK源码赏析之三:Java命令参数的读取处理流程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue 添加子路由 默认选中子路由
- 下一篇: java美元兑换,(Java实现) 美元