深入理解Java之jvm启动流程
jvm是java的核心运行平台,自然是个非常复杂的系统。当然了,说jvm是个平台,实际上也是个泛称。准确的说,它是一个java虚拟机的统称,它并不指具体的某个虚拟机。所以,谈到java虚拟机时,往往我们通常说的都是一些规范性质的东西。
那么,如果想要研究jvm是如何工作的,就不能是泛泛而谈了。我们必须要具体到某个指定的虚拟机实现,以便说清其过程。
1.说说openjdk
因为java实际上已经被oracle控制,而oracle本身是个商业公司,所以从某种程度上说,这里的java并不是完全开源的。我们称官方的jdk为oraclejdk.或者叫hotspotvm
与此同时,社区维护了一个完全开源的版本,openjdk。这两个jdk实际上,大部分是相同的,只是维护的进度不太一样,以及版权归属不一样。
所以,如果想研究jvm的实现,那么基于openjdk来做,是比较明智的选择。
如果想了解openjdk是如何设计的,以及它有什么高级特性,以及各种最佳实践,那么买一本书是最佳选择。
如果业有余力,想去了解了解源码的,那么可以到官网查看源码。openjdk8的源码地址为:http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/因为是国外网站的原因,速度不会很快。所以只是在网站上查看源码,还是有点累的。另外,没有ide的帮助,估计很少有人能够坚持下去。另外的下载地址,大家可以网上搜索下,资源总是有的,国人链接速度快。多花点心思找找。
当然要说明的一点是:一个没有设计背景,没有框架概念的源码阅读,都是而流氓。那样的工作,就像是空中楼阁,并不让人踏实。
2.谈谈C语言
C语言,一般作为我们的大学入门语言,或多或少都接触过。但要说精通,可能就是很少一部分人了。但我要说的是,只要学过C语言,对于大部分的程序阅读,基本上就不是问题了。
openjdk的实现中,其核心的一部分就是使用C语言写的,当然其他很多语言也是一样的。所以,C语言相当重要,在底层的世界里。这里只是说它重要,但并不代表它就一定最厉害,即不是写C语言的GG就比写JAVA的JJ厉害了。因为,工作不分高低,语言同样。只是各有所长罢了。重点不是在这里,在于思想。
C语言的编程几大流程:写代码(最核心)、编译、链接(最麻烦)、运行。
当然,最核心的自然是写代码。不对,最核心的是:做设计。
C语言中,以一个main()函数为入口,编写各种逻辑后,通过调用和控制main()方法,实现各种复杂逻辑。
所以,要研究一个项目,首先就是要找到其入口。然后根据目的,再进行各功能实现的通路学习。
C语言有极其灵活的语法,超级复杂的指针设计,以及各类似面向对象思想的结构体,以及随时可能操作系统获取信息的能力(各种链接)。所以,导致C语言有时确实比较难以读懂。这也是没办法的事,会很容易,精却很难。这是亘古不变的道理。是一个选择题,也是一道应用题。
一句话,会一点,就够吃瓜群众使用了。
3.openjdk的入口
上面说到,要研究一个C项目,首要就是找到其入口。那么,openjdk的入口在哪呢?
是在share/bin/main.c中,main()方法就是其入口。这个文件命名,够清晰了吧,明眼人一看就知道了。哈哈,不过一般地,我们还是需要通过查资料才知晓。
main.c是jvm的唯一main方法入口,其中,jdk被编译出来之后,会有许多的工作箱,如jmap,jps,jstack....这些工具箱的入口,实际也是这个main,只是它们包含了不同的子模块,从而达到不同工具的目的。
main.c的内容也不多,主要它也只是一个框架,为屏蔽各系统的差异。它的存在,主要是为引入JLI_LAUNCH()方法,相当于定义自己的main()方法。
/* *Thisfilecontainsthemainentrypointintothelaunchercode *thisistheonlyfilewhichwillberepeatedlycompiledbyother *tools.Therestofthefileswillbelinkedin. */ #include"defines.h" #ifdef_MSC_VER #if_MSC_VER>1400&&_MSC_VER<1600 /* *WhenbuildingforMicrosoftWindows,mainhasadependencyonmsvcr??.dll. * *WhenusingVisualStudio2005or2008,thatmustberecordedin *the[java,javaw].exe.manifestfile. * *AsofVS2010(ver=1600),theruntimesagainnolongerneedmanifests. * *Reference: *C:/ProgramFiles/MicrosoftSDKs/Windows/v6.1/include/crtdefs.h */ #include#ifdef_M_IX86 #pragmacomment(linker,"/manifestdependency:\"type='win32'"\ "name='"__LIBRARIES_ASSEMBLY_NAME_PREFIX".CRT'"\ "version='"_CRT_ASSEMBLY_VERSION"'"\ "processorArchitecture='x86'"\ "publicKeyToken='"_VC_ASSEMBLY_PUBLICKEYTOKEN"'\"") #endif/*_M_IX86*/ //ThismaynotbenecessaryyetfortheWindows64-bitbuild,butit //willbewhenthatbuildenvironmentisupdated.Needtotesttosee //ifitisharmless: #ifdef_M_AMD64 #pragmacomment(linker,"/manifestdependency:\"type='win32'"\ "name='"__LIBRARIES_ASSEMBLY_NAME_PREFIX".CRT'"\ "version='"_CRT_ASSEMBLY_VERSION"'"\ "processorArchitecture='amd64'"\ "publicKeyToken='"_VC_ASSEMBLY_PUBLICKEYTOKEN"'\"") #endif/*_M_AMD64*/ #endif/*_MSC_VER>1400&&_MSC_VER<1600*/ #endif/*_MSC_VER*/ /* *Entrypoint. */ //定义入口函数,JAVAW模式下使用WinMain(),否则使用main() #ifdefJAVAW char**__initenv; intWINAPI WinMain(HINSTANCEinst,HINSTANCEprevinst,LPSTRcmdline,intcmdshow) { intmargc; char**margv; constjbooleanconst_javaw=JNI_TRUE; __initenv=_environ; #else/*JAVAW*/ int main(intargc,char**argv) { intmargc; char**margv; constjbooleanconst_javaw=JNI_FALSE; #endif/*JAVAW*/ #ifdef_WIN32 //windows下的参数获取 { inti=0; if(getenv(JLDEBUG_ENV_ENTRY)!=NULL){ printf("Windowsoriginalmainargs:\n"); for(i=0;i<__argc;i++){ printf("wwwd_args[%d]=%s\n",i,__argv[i]); } } } JLI_CmdToArgs(GetCommandLine()); margc=JLI_GetStdArgc(); //addonemoretomarktheend margv=(char**)JLI_MemAlloc((margc+1)*(sizeof(char*))); { inti=0; StdArg*stdargs=JLI_GetStdArgs(); for(i=0;i 因为java语言被设计成跨平台的语言,那么如何跨平台呢?因为平台差异总是存在的,如果语言本身不关注平台,那么自然是有人在背后关注了平台,从而屏蔽掉了差异。是了,这就是虚拟机存在的意义。因此,在入口方法,我们就可以看到,它一上来就关注平台差异性。这是必须的。
4.openjdk的启动流程
有了上面的入口知识,好像是明白了一些道理。但是好像还是没有达到要理解启动过程的目的。不急,且听我慢慢道来。
我们启动一个虚拟机时,一般是使用java-classpath:xxx
xx.xx,或者是java-jar xx.jar。具体怎么用无所谓,重点是我们都是java这个应用程序启动的虚拟机。因此,我们便知道java程序,是我们启动jvm的核心开关。 4.0.jvm启动流程框架
废话不多说,java.c,是我们要研究的重要文件。它将是一个控制启动流程的实现超人。而它的入口,就是在main()中的定义JLI_Launch(...),所以让我们一睹真容。
//share/bin/java.c /* *Entrypoint. */ int JLI_Launch(intargc,char**argv,/*mainargc,argc*/ intjargc,constchar**jargv,/*javaargs*/ intappclassc,constchar**appclassv,/*appclasspath*/ constchar*fullversion,/*fullversiondefined*/ constchar*dotversion,/*dotversiondefined*/ constchar*pname,/*programname*/ constchar*lname,/*launchername*/ jbooleanjavaargs,/*JAVA_ARGS*/ jbooleancpwildcard,/*classpathwildcard*/ jbooleanjavaw,/*windows-onlyjavaw*/ jintergo/*ergonomicsclasspolicy*/ ) { intmode=LM_UNKNOWN; char*what=NULL; char*cpath=0; char*main_class=NULL; intret; InvocationFunctionsifn; jlongstart,end; charjvmpath[MAXPATHLEN]; charjrepath[MAXPATHLEN]; charjvmcfg[MAXPATHLEN]; _fVersion=fullversion; _dVersion=dotversion; _launcher_name=lname; _program_name=pname; _is_java_args=javaargs; _wc_enabled=cpwildcard; _ergo_policy=ergo; //初始化启动器 InitLauncher(javaw); //打印状态 DumpState(); //跟踪调用启动 if(JLI_IsTraceLauncher()){ inti; printf("Commandlineargs:\n"); for(i=0;i以上就是整个jvm虚拟机的启动过程框架了,基本上跑不掉几个点,就是解析命令行参数,设置参数到某范围内或者环境变量中。加载必要模块,传递变量存储。初始化系统。解析用户系统实现。当然一般地,就是会实现系统主循环,这个动作是由使用系统完成的,jvm只负责执行即可。
因为我们只是想了解大概,所以不以为然,只是其中任何一个点都足够研究很久很久了。抛开那些不说,捡个芝麻先。需要明白:懂得许多的道理却依然过不好这一生。只能安心做个吃瓜群众。
下面,就一些细节点,我们可以视兴趣,稍微深入了解下!
4.1.jre版本选择过程
以上框架中,几个重要的节点,我们可以再细化下实现。细节就不说,太复杂。首先,就是如何确定当前系统使用的jre版本,这很重要,它决定了应用系统是否可以运行的问题。因为有时候,系统的使用者并非开发者,一定存在正确的jre版本。没有jre的环境,所有java执行就会是一句空谈。
//java.c /* *TheSelectVersion()routineensuresthatanappropriateversionof *theJREisrunning.Thespecificationfortheappropriateversion *isobtainedfromeitherthemanifestofajarfile(preferred)or *fromcommandlineoptions. *Theroutinealsoparsessplashscreencommandlineoptionsand *passesontheirvaluesinprivateenvironmentvariables. */ staticvoid SelectVersion(intargc,char**argv,char**main_class) { char*arg; char**new_argv; char**new_argp; char*operand; char*version=NULL; char*jre=NULL; intjarflag=0; intheadlessflag=0; intrestrict_search=-1;/*-1impliesnotknown*/ manifest_infoinfo; charenv_entry[MAXNAMELEN+24]=ENV_ENTRY"="; char*splash_file_name=NULL; char*splash_jar_name=NULL; char*env_in; intres; /* *Iftheversionhasalreadybeenselected,set*main_class *withthevaluepassedthroughtheenvironment(ifany)and *simplyreturn. */ //_JAVA_VERSION_SET= if((env_in=getenv(ENV_ENTRY))!=NULL){ if(*env_in!='\0') *main_class=JLI_StringDup(env_in); return; } /* *ScanthroughtheargumentsforoptionsrelevanttomultipleJRE *support.Forreference,thecommandlinesyntaxisdefinedas: * *SYNOPSIS *java[options]class[argument...] * *java[options]-jarfile.jar[argument...] * *Asthescanisperformed,makeacopyoftheargumentlistwith *theversionspecificationoptions(newto1.5)removed,sothat *aversionlessthan1.5canbeexec'd. * *NotethatduetothesyntaxofthenativeWindowsinterface *CreateProcess(),processingsimilartothefollowingexistsin *theWindowsplatformspecificroutineExecJRE(injava_md.c). *Changeshereshouldbereproducedthere. */ new_argv=JLI_MemAlloc((argc+1)*sizeof(char*)); new_argv[0]=argv[0]; new_argp=&new_argv[1]; argc--; argv++; while((arg=*argv)!=0&&*arg=='-'){ if(JLI_StrCCmp(arg,"-version:")==0){ version=arg+9; }elseif(JLI_StrCmp(arg,"-jre-restrict-search")==0){ restrict_search=1; }elseif(JLI_StrCmp(arg,"-no-jre-restrict-search")==0){ restrict_search=0; }else{ if(JLI_StrCmp(arg,"-jar")==0) jarflag=1; /*dealwith"unfortunate"classpathsyntax*/ if((JLI_StrCmp(arg,"-classpath")==0||JLI_StrCmp(arg,"-cp")==0)&& (argc>=2)){ *new_argp++=arg; argc--; argv++; arg=*argv; } /* *CheckingforheadlesstoolkitoptioninthesomewayasAWTdoes: *"true"meanstrueandanyothervaluemeansfalse */ if(JLI_StrCmp(arg,"-Djava.awt.headless=true")==0){ headlessflag=1; }elseif(JLI_StrCCmp(arg,"-Djava.awt.headless=")==0){ headlessflag=0; }elseif(JLI_StrCCmp(arg,"-splash:")==0){ splash_file_name=arg+8; } *new_argp++=arg; } argc--; argv++; } if(argc<=0){/*Nooperand?Possiblylegitwith-[full]version*/ operand=NULL; }else{ argc--; *new_argp++=operand=*argv++; } while(argc-->0)/*Copyover[argument...]*/ *new_argp++=*argv++; *new_argp=NULL; /* *Ifthereisajarfile,readthemanifest.Ifthejarfilecan'tbe *read,themanifestcan'tbereadfromthejarfile,orthemanifest *iscorrupt,issuetheappropriateerrormessagesandexit. * *Evenifthereisn'tajarfile,constructamanifest_infostructure *containingthecommandlineinformation.It'saconvenientwaytocarry *thisdataaround. */ if(jarflag&&operand){ if((res=JLI_ParseManifest(operand,&info))!=0){ if(res==-1) JLI_ReportErrorMessage(JAR_ERROR2,operand); else JLI_ReportErrorMessage(JAR_ERROR3,operand); exit(1); } /* *Commandlinesplashscreenoptionshouldhaveprecedence *overthemanifest,sothemanifestdataisusedonlyif *splash_file_namehasnotbeeninitializedaboveduringcommand *lineparsing */ if(!headlessflag&&!splash_file_name&&info.splashscreen_image_file_name){ splash_file_name=info.splashscreen_image_file_name; splash_jar_name=operand; } }else{ info.manifest_version=NULL; info.main_class=NULL; info.jre_version=NULL; info.jre_restrict_search=0; } /* *Passingonsplashscreeninfoinenvironmentvariables */ if(splash_file_name&&!headlessflag){ char*splash_file_entry=JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY"=")+JLI_StrLen(splash_file_name)+1); JLI_StrCpy(splash_file_entry,SPLASH_FILE_ENV_ENTRY"="); JLI_StrCat(splash_file_entry,splash_file_name); putenv(splash_file_entry); } if(splash_jar_name&&!headlessflag){ char*splash_jar_entry=JLI_MemAlloc(JLI_StrLen(SPLASH_JAR_ENV_ENTRY"=")+JLI_StrLen(splash_jar_name)+1); JLI_StrCpy(splash_jar_entry,SPLASH_JAR_ENV_ENTRY"="); JLI_StrCat(splash_jar_entry,splash_jar_name); putenv(splash_jar_entry); } /* *TheJRE-VersionandJRE-Restrict-Searchvalues(ifany)fromthe *manifestareoverwrittenbyanyspecifiedonthecommandline. */ if(version!=NULL) info.jre_version=version; if(restrict_search!=-1) info.jre_restrict_search=restrict_search; /* *"Valid"returns(otherthanunrecoverableerrors)follow.Set *main_classasaside-effectofthisroutine. */ if(info.main_class!=NULL) *main_class=JLI_StringDup(info.main_class); /* *Ifnoversionselectioninformationisfoundeitheronthecommand *lineorinthemanifest,simplyreturn. */ if(info.jre_version==NULL){ JLI_FreeManifest(); JLI_MemFree(new_argv); return; } /* *Checkforcorrectsyntaxoftheversionspecification(JSR56). */ if(!JLI_ValidVersionString(info.jre_version)){ JLI_ReportErrorMessage(SPC_ERROR1,info.jre_version); exit(1); } /* *FindtheappropriateJVMonthesystem.Justtobeasforgivingas *possible,ifthestandardalgorithmsdon'tlocateanappropriate *jre,checktoseeiftheonerunningwillsatisfytherequirements. *Thiscanhappenonsystemswhichhaven'tbeenset-upformultiple *JREsupport. */ jre=LocateJRE(&info); JLI_TraceLauncher("JRE-Version=%s,JRE-Restrict-Search=%sSelected=%s\n", (info.jre_version?info.jre_version:"null"), (info.jre_restrict_search?"true":"false"),(jre?jre:"null")); if(jre==NULL){ if(JLI_AcceptableRelease(GetFullVersion(),info.jre_version)){ JLI_FreeManifest(); JLI_MemFree(new_argv); return; }else{ JLI_ReportErrorMessage(CFG_ERROR4,info.jre_version); exit(1); } } /* *IfI'mnotthechosenone,execthechosenone.Returningfrom *ExecJREindicatesthatIamindeedthechosenone. * *Theprivateenvironmentvariable_JAVA_VERSION_SETisusedto *preventthechosenonefromre-readingthemanifestfileand *usingthevaluesfoundwithintooverridethe(potential)command *lineflagsstrippedfromargv(becausethetargetmaynot *understandthem).PassingtheMainClassvalueisanoptimization *toavoidlocating,expandingandparsingthemanifestextra *times. */ if(info.main_class!=NULL){ if(JLI_StrLen(info.main_class)<=MAXNAMELEN){ (void)JLI_StrCat(env_entry,info.main_class); }else{ JLI_ReportErrorMessage(CLS_ERROR5,MAXNAMELEN); exit(1); } } (void)putenv(env_entry); ExecJRE(jre,new_argv); JLI_FreeManifest(); JLI_MemFree(new_argv); return; }逻辑也不复杂,大概就是,解析参数,读取manifest文件,jre版本校验,加载jre以便确认是否存在,最后将相关环境变量放置好。
4.2.加载VM模块
加载VM是非常重要的一个工作。它是一个平台相关的实现,我们看下windows版本的实现吧。
//share/windows/bin/java_md.c /* *Loadajvmfrom"jvmpath"andinitializetheinvocationfunctions. */ jboolean LoadJavaVM(constchar*jvmpath,InvocationFunctions*ifn) { HINSTANCEhandle; JLI_TraceLauncher("JVMpathis%s\n",jvmpath); /* *TheMicrosoftCRuntimeLibraryneedstobeloadedfirst.Acopyis *assumedtobepresentinthe"JREpath"directory.Ifitisnotfound *there(or"JREpath"failstoresolve),skiptheexplicitloadandlet *naturetakeitscourse,whichislikelytobeafailuretoexecute. * */ LoadMSVCRT(); //windows中是通过路径加载dll文件实现 /*LoadtheJavaVMDLL*/ if((handle=LoadLibrary(jvmpath))==0){ JLI_ReportErrorMessage(DLL_ERROR4,(char*)jvmpath); returnJNI_FALSE; } /*Nowgetthefunctionaddresses*/ //获取虚拟机操作内存地址 ifn->CreateJavaVM= (void*)GetProcAddress(handle,"JNI_CreateJavaVM"); ifn->GetDefaultJavaVMInitArgs= (void*)GetProcAddress(handle,"JNI_GetDefaultJavaVMInitArgs"); if(ifn->CreateJavaVM==0||ifn->GetDefaultJavaVMInitArgs==0){ JLI_ReportErrorMessage(JNI_ERROR1,(char*)jvmpath); returnJNI_FALSE; } returnJNI_TRUE; }可见,最重要的工作是被封装到JRE中的,应用层面只是调用JRE的方法即可。在windows中通过加载msvcrt模块完成工作,然后抽取vm的两个方法签名到ifn中,以便后续实用。
4.3.解析参数信息
通过参数解析,我们就可以如何设置参数了。更深层次的理解。
//实际就是语法规范 /* *Parsescommandlinearguments.ReturnsJNI_FALSEiflauncher *shouldexitwithoutstartingvm,returnsJNI_TRUEifvmneeds *tobestartedtoprocessgivenoptions.*pret(thelauncher *processreturnvalue)issetto0foranormalexit. */ staticjboolean ParseArguments(int*pargc,char***pargv, int*pmode,char**pwhat, int*pret,constchar*jrepath) { intargc=*pargc; char**argv=*pargv; intmode=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; }elseif(JLI_StrCmp(arg,"-jar")==0){ ARG_CHECK(argc,ARG_ERROR2,arg); mode=LM_JAR; }elseif(JLI_StrCmp(arg,"-help")==0|| JLI_StrCmp(arg,"-h")==0|| JLI_StrCmp(arg,"-?")==0){ printUsage=JNI_TRUE; returnJNI_TRUE; }elseif(JLI_StrCmp(arg,"-version")==0){ printVersion=JNI_TRUE; returnJNI_TRUE; }elseif(JLI_StrCmp(arg,"-showversion")==0){ showVersion=JNI_TRUE; }elseif(JLI_StrCmp(arg,"-X")==0){ printXUsage=JNI_TRUE; returnJNI_TRUE; /* *Thefollowingcasechecksfor-XshowSettingsOR-XshowSetting:SUBOPT. *Inthelattercase,anySUBOPTvaluenotrecognizedwilldefaultto"all" */ }elseif(JLI_StrCmp(arg,"-XshowSettings")==0|| JLI_StrCCmp(arg,"-XshowSettings:")==0){ showSettings=arg; }elseif(JLI_StrCmp(arg,"-Xdiag")==0){ AddOption("-Dsun.java.launcher.diag=true",NULL); /* *Thefollowingcaseprovidebackwardcompatibilitywithold-style *commandlineoptions. */ }elseif(JLI_StrCmp(arg,"-fullversion")==0){ JLI_ReportMessage("%sfullversion\"%s\"",_launcher_name,GetFullVersion()); returnJNI_FALSE; }elseif(JLI_StrCmp(arg,"-verbosegc")==0){ AddOption("-verbose:gc",NULL); }elseif(JLI_StrCmp(arg,"-t")==0){ AddOption("-Xt",NULL); }elseif(JLI_StrCmp(arg,"-tm")==0){ AddOption("-Xtm",NULL); }elseif(JLI_StrCmp(arg,"-debug")==0){ AddOption("-Xdebug",NULL); }elseif(JLI_StrCmp(arg,"-noclassgc")==0){ AddOption("-Xnoclassgc",NULL); }elseif(JLI_StrCmp(arg,"-Xfuture")==0){ AddOption("-Xverify:all",NULL); }elseif(JLI_StrCmp(arg,"-verify")==0){ AddOption("-Xverify:all",NULL); }elseif(JLI_StrCmp(arg,"-verifyremote")==0){ AddOption("-Xverify:remote",NULL); }elseif(JLI_StrCmp(arg,"-noverify")==0){ AddOption("-Xverify:none",NULL); }elseif(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); }elseif(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); }elseif(JLI_StrCmp(arg,"-checksource")==0|| JLI_StrCmp(arg,"-cs")==0|| JLI_StrCmp(arg,"-noasyncgc")==0){ /*Nolongersupported*/ JLI_ReportErrorMessage(ARG_WARN,arg); }elseif(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){ ;/*Ignoremachineindependentoptionsalreadyhandled*/ }elseif(ProcessPlatformOption(arg)){ ;/*Processingofplatformdependentoptions*/ }elseif(RemovableOption(arg)){ ;/*Donotpassoptiontovm.*/ }else{ AddOption(arg,NULL); } } if(--argc>=0){ *pwhat=*argv++; } if(*pwhat==NULL){ *pret=1; }elseif(mode==LM_UNKNOWN){ /*defaulttoLM_CLASSif-jarand-cpoptionare *notspecified*/ mode=LM_CLASS; } if(argc>=0){ *pargc=argc; *pargv=argv; } *pmode=mode; returnJNI_TRUE; } /* *injectthe-Dsun.java.commandpseudopropertyintotheargsstructure *thispseudopropertyisusedintheHotSpotVMtoexposethe *JavaclassnameandargumentstothemainmethodtotheVM.The *HotSpotVMusesthispseudopropertytostoretheJavaclassname *(orjarfilename)andtheargumentstotheclass'smainmethod *totheinstrumentationmemoryregion.Thesun.java.commandpseudo *propertyisnotexportedbyHotSpottotheJavalayer. */ void SetJavaCommandLineProp(char*what,intargc,char**argv) { inti=0; size_tlen=0; char*javaCommand=NULL; char*dashDstr="-Dsun.java.command="; if(what==NULL){ /*unexpected,oneoftheseshouldbeset.justreturnwithout *settingtheproperty */ return; } /*determinetheamountofmemorytoallocateassuming *theindividualcomponentswillbespaceseparated */ len=JLI_StrLen(what); for(i=0;i-Xxxxx,--xxx格式配置,如-Xms1024G,--noclassgc...然后解析出来。最后通过AddOption()存储起来。
4.4.jvm初始化
好像我们一直讨论的都是这个,但是实际上里面还有一个真正的jvm的初始化过程。这里方才会接入真正的java程序,也才大家所关心的地方。
//java.c JVMInit(InvocationFunctions*ifn,jlongthreadStackSize, intargc,char**argv, intmode,char*what,intret) { ShowSplashScreen(); returnContinueInNewThread(ifn,threadStackSize,argc,argv,mode,what,ret); } /* *Displaysthesplashscreenaccordingtothejarfilename *andimagefilenamesstoredinenvironmentvariables */ void ShowSplashScreen() { constchar*jar_name=getenv(SPLASH_JAR_ENV_ENTRY); constchar*file_name=getenv(SPLASH_FILE_ENV_ENTRY); intdata_size; void*image_data=NULL; floatscale_factor=1; char*scaled_splash_name=NULL; if(file_name==NULL){ return; } scaled_splash_name=DoSplashGetScaledImageName( jar_name,file_name,&scale_factor); if(jar_name){ if(scaled_splash_name){ image_data=JLI_JarUnpackFile( jar_name,scaled_splash_name,&data_size); } if(!image_data){ scale_factor=1; image_data=JLI_JarUnpackFile( jar_name,file_name,&data_size); } if(image_data){ DoSplashInit(); DoSplashSetScaleFactor(scale_factor); DoSplashLoadMemory(image_data,data_size); JLI_MemFree(image_data); } }else{ DoSplashInit(); if(scaled_splash_name){ DoSplashSetScaleFactor(scale_factor); DoSplashLoadFile(scaled_splash_name); }else{ DoSplashLoadFile(file_name); } } if(scaled_splash_name){ JLI_MemFree(scaled_splash_name); } DoSplashSetFileJarName(file_name,jar_name); /* *Donewithallcommandlineprocessingandpotentialre-execsso *cleanuptheenvironment. */ (void)UnsetEnv(ENV_ENTRY); (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY); (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY); JLI_MemFree(splash_jar_entry); JLI_MemFree(splash_file_entry); } int ContinueInNewThread(InvocationFunctions*ifn,jlongthreadStackSize, intargc,char**argv, intmode,char*what,intret) { /* *Ifuserdoesn'tspecifystacksize,checkifVMhasapreference. *NotethatHotSpotnolongersupportsJNI_VERSION_1_1butitwill *returnitsdefaultstacksizethroughtheinitargsstructure. */ if(threadStackSize==0){ structJDK1_1InitArgsargs1_1; memset((void*)&args1_1,0,sizeof(args1_1)); args1_1.version=JNI_VERSION_1_1; ifn->GetDefaultJavaVMInitArgs(&args1_1);/*ignorereturnvalue*/ if(args1_1.javaStackSize>0){ threadStackSize=args1_1.javaStackSize; } } {/*CreateanewthreadtocreateJVMandinvokemainmethod*/ JavaMainArgsargs; intrslt; args.argc=argc; args.argv=argv; args.mode=mode; args.what=what; args.ifn=*ifn; rslt=ContinueInNewThread0(JavaMain,threadStackSize,(void*)&args); /*Ifthecallerhasdeemedthereisanerrorwe *simplyreturnthat,otherwisewereturnthevalueof *thecallee */ return(ret!=0)?ret:rslt; } }看起来,jvm是通过一个新线程去运行应用系统的。在将执行控制权交由java代码后,它的主要作用,就是不停地接收命令,执行命令。从而变成一个真正的执行机器。
到此这篇关于深入理解Java之jvm启动流程的文章就介绍到这了,更多相关Java之jvm启动流程内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!