Startup of Java Virtual Machine and program running
This article is from the perspective of OpenJDK source code.
java -classpath . hello
Later, how does java.exe execute from the main function, start the virtual machine, and execute the code in the bytecode.
Lab Environment
To understand how a system runs, you can't simply see it. You must actually run, debug, and modify the system to understand the system's action methods.
At first, I used Visual Studio 2010 to debug and run OpenJDK-Research, a GitHub project, on windows 7 64-bit platform. But later I found that this project only compiled the HotSpot virtual machine,java.exe
Not compiled.
First, we can understandjava.exe
And virtual machines. The HotSpot compiled by Visual Studio is a virtual machine and is used as a dynamic link library.java.exe
Loaded.java.exe
Resolves the parameters and loads the Virtual Machine Link Library. It needs to call functions in the virtual machine to execute Java program functions. Therefore, you cannot find the Startup Program in the source code of HotSpot.main
Function, originally in openjdk7, the virtual machine has an initiator in the directoryopenjdk/hotspot/src/share/tools/launcher/java.c
The main function can be found, but in openjdk8, this starter is missing and put inopenjdk/jdk
Directory insteadopenjdk/hotspot
Directory, causing harm to our learning process.
So I debugged it on the linux platform later, because on the windows platform, I have never compiled the entire openjdk8 successfully and cannot compile it.java.exe
, Only compiledhotspot
You cannot see the execution of the main function. For more information about how to compile and debug openjdk8 on the linux platform, refer to another article on how to compile openjdk8on Ubuntu 12.04.
Call Stack
jdk8u/jdk/src/share/bin/main.c::WinMain/main jdk8u/jdk/src/share/bin/java.c::JLI_Launch jdk8u/jdk/src/solaris/bin/java_md_solinux.c::LoadJavaVM # Load JVM Library: libjvm.so jdk8u/jdk/src/solaris/bin/java_md_solinux.c::JVMInit # Create JVM jdk8u/jdk/src/share/bin/java.c::ContinueInNewThread jdk8u/jdk/src/solaris/bin/java_md_solinux.c::ContinueInNewThread0(JavaMain, threadStackSize, (void*)&args); pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) jdk8u/jdk/src/share/bin/java.c::JavaMain jdk8u/jdk/src/share/bin/java.c::InitializeJVM jdk8u\hotspot\src\share\vm\prims\jni.cpp::JNI_CreateJavaVM
Execution Process
- Main. c (jdk8u/jdk/src/share/bin/main. c)
#ifdef JAVAWchar **__initenv;int WINAPIWinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow){ int margc; char** margv; const jboolean const_javaw = JNI_TRUE; __initenv = _environ;#else /* JAVAW */intmain(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] = %s\n", 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);}
This is the legendmain
It can be seen that the function executes different code segments for the operating system to determine whether to use Windows, and finally callsJLI_Launch
Function.
- JLI_Lanuch (jdk8u/jdk/src/share/bin/java. c)
intJLI_Launch(int argc, char ** argv, /* main argc, argc */ int jargc, const char** jargv, /* java args */ int appclassc, const char** appclassv, /* app classpath */ const char* fullversion, /* full version defined */ const char* dotversion, /* dot version defined */ const char* pname, /* program name */ const char* lname, /* launcher name */ jboolean javaargs, /* JAVA_ARGS */ jboolean cpwildcard, /* classpath wildcard*/ jboolean javaw, /* windows-only javaw */ jint ergo /* ergonomics class policy */){... if (!LoadJavaVM(jvmpath, &ifn)) { return(6); }... return JVMInit(&ifn, threadStackSize, argc, argv, mode, what, ret);}
Here we can see the meaning of each JLI_Lanuch parameter. I have listed the key code, whereLoadJavaVM
Load and initialize the dynamic link library of the VM.ifn
The function pointer in the HotSpot VM is like this to the initiatorjava
Provides functions.
- LoadJavaVM (jdk8u/jdk/src/solaris/bin/java_md_solinux.c)
This function involves a dynamic link library. different operating systems have different interfaces. This function is for linux.
jbooleanLoadJavaVM(const char *jvmpath, InvocationFunctions *ifn){ ... libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL); ... ifn->CreateJavaVM = (CreateJavaVM_t) dlsym(libjvm, "JNI_CreateJavaVM"); ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); ifn->GetCreatedJavaVMs = (GetCreatedJavaVMs_t) dlsym(libjvm, "JNI_GetCreatedJavaVMs"); ...
Here we can see the code for loading the dynamic link library and initializing the FN data structure. In my debugging version,javapath
Point to the previously compiled Dynamic Link Libraryjdk8u/build/fastdebug/jdk/lib/i386/server/libjvm.so
.
- JVM_Init (jdk8u/jdk/src/solaris/bin/java_md_solinux.c)
BackJLI_Lanuch
Function.JVM_Init
This function starts a new thread.
intJVMInit(InvocationFunctions* ifn, jlong threadStackSize, int argc, char **argv, int mode, char *what, int ret){ ShowSplashScreen(); return ContinueInNewThread(ifn, threadStackSize, argc, argv, mode, what, ret);}
ContinueInNewThread
Will call another functionContinueInNewThread0
Start thread and executeJavaMain
Function:
intContinueInNewThread0(int (JNICALL *continuation)(void *), jlong stack_size, void * args) {... if (pthread_create(&tid, &attr, (void *(*)(void*))continuation, (void*)args) == 0) { void * tmp; pthread_join(tid, &tmp); rslt = (int)tmp; } else { /* * Continue execution in current thread if for some reason (e.g. out of * memory/LWP) a new thread can't be created. This will likely fail * later in continuation as JNI_CreateJavaVM needs to create quite a * few new threads, anyway, just give it a try.. */ rslt = continuation(args); }...
- JavaMain (jdk8u/jdk/src/share/bin/java. c)
This function initializes the virtual machine, loads various types, and executesmain
Function. The annotations are detailed.
int JNICALLJavaMain(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; // actual application class being launched jmethodID mainID; jobjectArray mainArgs; int ret = 0; jlong start, end; RegisterThread(); /* Initialize the virtual machine */ start = CounterGet(); if (!InitializeJVM(&vm, &env, &ifn)) { JLI_ReportErrorMessage(JVM_ERROR1); exit(1); } ... ret = 1; /* * Get the application's main class. * * See bugid 5030265. The Main-Class name has already been parsed * from the manifest, but not parsed properly for UTF-8 support. * 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. However, it has * also been discovered that passing some character sets through * the environment has "strange" behavior on some variants of * Windows. Hence, maybe the manifest parsing code local to the * launcher should never be enhanced. * * Hence, future work should either: * 1) Correct the local parsing code and verify that the * Main-Class attribute gets properly passed through * all environments, * 2) Remove the vestages of maintaining main_class through * the environment (and remove these comments). * * This method also correctly handles launching existing JavaFX * applications that may or may not have a Main-Class manifest entry. */ mainClass = LoadMainClass(env, mode, what); CHECK_EXCEPTION_NULL_LEAVE(mainClass); /* * In some cases when launching an application that needs a helper, e.g., a * JavaFX application with no main method, the mainClass will not be the * applications own main class but rather a helper class. To keep things * consistent in the UI we need to track and report the application main class. */ appClass = GetApplicationClass(env); NULL_CHECK_RETURN_VALUE(appClass, -1); /* * PostJVMInit uses the class name as the application name for GUI purposes, * for example, on OSX this sets the application name in the menu bar for * both SWT and JavaFX. So we'll pass the actual application class here * instead of mainClass as that may be a launcher or helper class instead * of the application class. */ PostJVMInit(env, appClass, vm); /* * The LoadMainClass not only loads the main class, it will also ensure * that the main method's signature is correct, therefore further checking * is not required. The main method is invoked here so that extraneous java * stacks are not in the application stack trace. */ mainID = (*env)->GetStaticMethodID(env, mainClass, "main", "([Ljava/lang/String;)V"); CHECK_EXCEPTION_NULL_LEAVE(mainID); /* Build platform specific argument array */ mainArgs = CreateApplicationArgs(env, argv, argc); CHECK_EXCEPTION_NULL_LEAVE(mainArgs); /* Invoke main method. */ (*env)->CallStaticVoidMethod(env, mainClass, mainID, mainArgs); /* * The launcher's exit code (in the absence of calls to * System.exit) will be non-zero if main threw an exception. */ ret = (*env)->ExceptionOccurred(env) == NULL ? 0 : 1; LEAVE();}
Note that the InitializeJVM function will call the previously initializedifn
In the data structureCreateJavaVM
Function.
- InitializeJVM (jdk8u/jdk/src/share/bin/java. c: InitializeJVM)
static jbooleanInitializeJVM(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;}
ifn->CreateJavaVM
Point to the dynamic Connection Library of the Virtual MachineJNI_CreateJavaVM
Function, this function will actually create a virtual machine.
- JNI_CreateJavaVM (jdk8u \ hotspot \ src \ share \ vm \ prims \ jni. cpp)
_JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) { ... result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again); if (result == JNI_OK) { JavaThread *thread = JavaThread::current(); /* thread is thread_in_vm here */ *vm = (JavaVM *)(&main_vm); *(JNIEnv**)penv = thread->jni_environment(); // Tracks the time application was running before GC RuntimeService::record_application_start(); // Notify JVMTI if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_start(thread); } ... } ...}
Thecreate_vm
A function is the key to VM initialization. It initializes most of the VM's components.
This function is located injdk8u\hotspot\src\share\vm\prims\jni.cpp
.
The first function that I used to debug in Windows is the HotSpot dynamic link library.JNI_CreateJavaVM
, The previous calls are all located injava.exe
Code. Because Windowsjava.exe
We didn't compile it by ourselves, and we couldn't see the call relationship in it. As shown in:
At the same time, we can see two threads <喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHA + CjxpbWcgc3JjPQ = "http://www.2cto.com/uploadfile/Collfiles/20140823/20140823094904303.png" alt = "">