概述
承接上一谈
OpenJDK源码赏析之一:漫谈java的历史渊源_星空_AZ的博客-CSDN博客
JAVA从启动到第一个函数执行的发生的流程:
WinMain->JLI_Launch->JVMInit->NewThread->JavaMain->initializateJVM->CreatJavaVM->LoadMainClass->GetStaticMethodID
看一个程序首先要找它的启动入口
OpenJDK的如下目录有着main程序的启动入口:
打开后是程序的入口,main的函数如下:
int WINAPI
WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow)
{
int margc;
char** margv;
const jboolean const_javaw = JNI_TRUE;
__initenv = _environ;
#else /* JAVAW */
int
main(int argc, char **argv)
{
int margc;
char** margv;
const jboolean const_javaw = JNI_FALSE;
#endif /* JAVAW */
#ifdef _WIN32
{
int i = 0;
if (getenv(JLDEBUG_ENV_ENTRY) != NULL) {
printf("Windows original main args:n");
for (i = 0 ; i < __argc ; i++) {
printf("wwwd_args[%d] = %sn", i, __argv[i]);
}
}
}
JLI_CmdToArgs(GetCommandLine());
margc = JLI_GetStdArgc();
// add one more to mark the end
margv = (char **)JLI_MemAlloc((margc + 1) * (sizeof(char *)));
{
int i = 0;
StdArg *stdargs = JLI_GetStdArgs();
for (i = 0 ; i < margc ; i++) {
margv[i] = stdargs[i].arg;
}
margv[i] = NULL;
}
#else /* *NIXES */
margc = argc;
margv = argv;
#endif /* WIN32 */
return JLI_Launch(margc, margv,
sizeof(const_jargs) / sizeof(char *), const_jargs,
sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
FULL_VERSION,
DOT_VERSION,
(const_progname != NULL) ? const_progname : *margv,
(const_launcher != NULL) ? const_launcher : *margv,
(const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,
const_cpwildcard, const_javaw, const_ergo_class);
}
可以看到最后运行一个JLI_Launch的函数,JLI的全称为Java Native Interface,是java调用非java代码的接口,这个函数在java.c中, 找到java.c中该函数的位置
看到 CreateExecutionEnvironment,为创建执行环境
跳转到该函数实现位置
其实现了以下几个功能
①判断环境为32位或者64位
②得到JRE的路径
③ReadKnownVms()得到JVM.cfg文件(该文件为java的配置文件)
④CheckJvmType确认当前的jvm类型
⑤GetJVMPath根据上一步确定的JVM类型,找到对应的JVM.dll文件
继续回到java.c中的JLI_Launch函数,下面执行LoadJavaVM
跳转到该函数其实现了加载dll库,并绑定函数可以调用dll中的
LoadLibrary链接到DLL库(LoadLibrary为加载动态链接库),此库为jvm.dll
把JVM.dll文件中定义的函数JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs的指针绑定到InvocationFunctions变量的CreateJavaVM和GetDefaultJavaVMInitArgs函数指针变量上;
当装载好虚拟机所需要的环境之后,回到JLI_Launch函数最后一步要执行的JVMInit
跳转到JVMInit后,开始通过ContinueInNewThread创建新的Java进程
在ContinueInNewThread下有个函数ContinueInNewThread0,执行了当前的主方法JavaMain
在JavaMain中有一个InitializeJVM
初始化虚拟机
/*
* 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 %ldn", (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;
}
最后有CreatJavaVM,初始化虚拟机
最后创建Java虚拟机进程后,回到JavaMain函数下面有这么一行:
把mainClass赋值为我们写的调用的主函数,以下为LoadMainClass源码
/*
* Loads a class and verifies that the main class is present and it is ok to
* call it for more details refer to the java implementation.
* 加载一个类并验证主类是否存在,可以调用它以获取更多详细信息,请参阅java实现。
*/
static jclass
LoadMainClass(JNIEnv *env, int mode, char *name)
{
jmethodID mid;
jstring str;
jobject result;
jlong start, end;
jclass cls = GetLauncherHelperClass(env);
NULL_CHECK0(cls);
if (JLI_IsTraceLauncher()) {
start = CounterGet();
}
NULL_CHECK0(mid = (*env)->GetStaticMethodID(env, cls,
"checkAndLoadMain",
"(ZILjava/lang/String;)Ljava/lang/Class;"));
str = NewPlatformString(env, name);
result = (*env)->CallStaticObjectMethod(env, cls, mid, USE_STDERR, mode, str);
if (JLI_IsTraceLauncher()) {
end = CounterGet();
printf("%ld micro seconds to load main classn",
(long)(jint)Counter2Micros(end-start));
printf("----%s----n", JLDEBUG_ENV_ENTRY);
}
return (jclass)result;
}
mainClass赋值完成以后,返回JavaMain函数接着执行下面的操作:
用CallStaticVoidMethod调用我们在Java里面写的Java入口函数mainClass
至此从java启动到运行第一个类的全逻辑已经理了一遍
想知道在命令行中输入java -help的流程吗,我将在下一篇将分析cmd下java命令行的读取
OpenJDK源码赏析之三:cmd下Java命令参数的读取_星空_AZ的博客-CSDN博客
最后
以上就是典雅雨为你收集整理的OpenJDK源码赏析之二:java虚拟机启动流程到首函数调用全流程的全部内容,希望文章能够帮你解决OpenJDK源码赏析之二:java虚拟机启动流程到首函数调用全流程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复