在学启动的时候, 我一直在想一个以前的java问题,就是Tomcat有没有Main函数, 答案肯定是有! 那么jvm做为一个C++应用程序, 他也肯定有man函数, 我们坚定这一点, 然后再去看代码
我们可以通过全局搜索可以定位到main函数的位置,如下图所示:
点进去文件可以看到jvm对不同的处理器32位/64位和不同的启动类型javaw/java做不了同的处理.
JAVAW 的启动头是
int WINAPI
WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow)
{
int margc;
char** margv;
int jargc;
char** jargv;
const jboolean const_javaw = JNI_TRUE;
__initenv = _environ;
java的启动头是
JNIEXPORT int
main(int argc, char **argv)
{
int margc;
char** margv;
int jargc;
char** jargv;
const jboolean const_javaw = JNI_FALSE;
往下的方法体中可以看到大都是对参数进行的处理, 直到这个文件的最后,开始Launch启动
return JLI_Launch(margc, margv,
jargc, (const char**) jargv,
0, NULL,
VERSION_STRING,
DOT_VERSION,
(const_progname != NULL) ? const_progname : *margv,
(const_launcher != NULL) ? const_launcher : *margv,
jargc > 0,
const_cpwildcard, const_javaw, 0)
该方法的实现是在src/java.base/share/native/libjli/java.c
这个目录下
在这个方法中, 我们可以看到, 主要是以下几步:
调用方法CreateExecutionEnvironment
创建运行环境
调用方法LoadJavaVM
去加载libjvm
调用方法ParseArguments
去解析参数
最后调用JVMInit
去启动JVM
这个方法就跟操作系统有关了,如下图所示不同的系统会去执行不同的文件的中代码
在对应系统的JVMInit
的方法中, 会调用java.c
中的ContinueInNewThread
方法,并在方法ContinueInNewThread
中调用不同操作系统的ContinueInNewThread0
方法,如下图所示:
这样我们就来到了第一天,用Clion调试JDK源码时的JavaMain方法
这里还是以打印版本号为例,可以看到在444行,有如下代码:
if (printVersion || showVersion) {
PrintJavaVersion(env, showVersion);
CHECK_EXCEPTION_LEAVE(0);
if (printVersion) {
LEAVE();
}
}
可知实际调用的是PrintJavaVersion(env,showVersion)
这个方法.
其实现如下:
static void
PrintJavaVersion(JNIEnv *env, jboolean extraLF)
{
jclass ver;
jmethodID print;
// 找到指定的类
NULL_CHECK(ver = FindBootStrapClass(env, "java/lang/VersionProps"));
// 找到指定的方法
NULL_CHECK(print = (*env)->GetStaticMethodID(env,
ver,
(extraLF == JNI_TRUE) ? "println" : "print",
"(Z)V"
)
);
// 调用这个方法
(*env)->CallStaticVoidMethod(env, ver, print, printTo);
}
我们在Idea中,引入11的JDK , 然后就可以看到对应的输出
至此,java -version的执行过程,我们是已经了解了, 而且借着java -version
我们还了解到了jvm虚拟机启动的过程. 这部分是后面的基础, 希望小伙伴们能跟着小刀一起,落实这方面的知识,加油!