Hotspot Internals in Action(3):HelloWorld
1、CreateJavaVM
(见jni.cpp:JNI_CreateJavaVM)
函数原型:

主要代码:

为vm、penv赋值。
这里顺便提一下VM退出的两条退出路径(见/src/share/vm/runtime/thread.cpp):
destroy_vm:called from jni_DestroyJavaVM() when the program falls off the endof main().
vm_exit(): when the program calls System.exit() to return a value or whenthere is a serious error in VM.
The two shutdown paths are not exactly thesame, but they share Shutdown.shutdown() at Java level and before_exit() andVM_Exit op at VM level.
destroy_vm退出流程:
? + Wait until we are the last non-daemon thread to execute
// <-- every thing is still working at this moment -->
? + Call java.lang.Shutdown.shutdown(), which will invoke Java level
// shutdown hooks, run finalizers if finalization-on-exit
? + Call before_exit(), prepare for VM exit
// > run VM level shutdown hooks (they are registered throughJVM_OnExit(),
// currently the only user of this mechanism is File.deleteOnExit())
// > stop flat profiler, StatSampler, watcher thread, CMS threads,
// post thread end and vm death events to JVMTI,
// stop signal thread
? + Call JavaThread::exit(), it will:
// > release JNI handle blocks, remove stack guard pages
// > remove this thread from Threads list
// <-- no more Java code from this thread after this point -->
? + Stop VM thread, it will bring the remaining VM to a safepoint andstop
// the compiler threads at safepoint
// <-- do not use anything that could get blocked by Safepoint -->
? + Disable tracing at JNI/JVM barriers
? + Set _vm_exited flag for threads that are still running native code
? + Delete this thread
? + Call exit_globals()
// > deletes tty
// > deletes PerfMemory resources
? + Return to caller
2、JavaVM
见:/src/share/vm/prims/jni.h


3、JNIEnv

结构体JNINativeInterface_中包含了大量的函数指针(详见jni.h),这些函数包括:


这些函数指针在jni.cpp中可以见到赋值:
// Structure containing all jni functions
structJNINativeInterface_ jni_NativeInterface = {
NULL, NULL, NULL, NULL,
jni_GetVersion, jni_DefineClass, jni_FindClass,
jni_FromReflectedMethod, jni_FromReflectedField, jni_ToReflectedMethod,
jni_GetSuperclass, jni_IsAssignableFrom, jni_ToReflectedField,
jni_Throw, jni_ThrowNew, jni_ExceptionOccurred,
jni_ExceptionDescribe, jni_ExceptionClear, jni_FatalError,
jni_PushLocalFrame, jni_PopLocalFrame,
jni_NewGlobalRef, jni_DeleteGlobalRef, jni_DeleteLocalRef,
jni_IsSameObject, jni_NewLocalRef, jni_EnsureLocalCapacity,
jni_AllocObject, jni_NewObject,
jni_NewObjectV, jni_NewObjectA,
jni_GetObjectClass, jni_IsInstanceOf,
jni_GetMethodID,
jni_CallObjectMethod, jni_CallObjectMethodV, jni_CallObjectMethodA,
jni_CallBooleanMethod, jni_CallBooleanMethodV,jni_CallBooleanMethodA,
jni_CallByteMethod, jni_CallByteMethodV, jni_CallByteMethodA,
jni_CallCharMethod, jni_CallCharMethodV, jni_CallCharMethodA,
jni_CallShortMethod, jni_CallShortMethodV, jni_CallShortMethodA,
jni_CallIntMethod, jni_CallIntMethodV, jni_CallIntMethodA,
jni_CallLongMethod, jni_CallLongMethodV, jni_CallLongMethodA,
jni_CallFloatMethod, jni_CallFloatMethodV, jni_CallFloatMethodA,
jni_CallDoubleMethod, jni_CallDoubleMethodV,jni_CallDoubleMethodA,
jni_CallVoidMethod, jni_CallVoidMethodV, jni_CallVoidMethodA,
jni_CallNonvirtualObjectMethod, jni_CallNonvirtualObjectMethodV,
jni_CallNonvirtualObjectMethodA, jni_CallNonvirtualBooleanMethod,
jni_CallNonvirtualBooleanMethodV, jni_CallNonvirtualBooleanMethodA,
jni_CallNonvirtualByteMethod, jni_CallNonvirtualByteMethodV,
jni_CallNonvirtualByteMethodA, jni_CallNonvirtualCharMethod,
jni_CallNonvirtualCharMethodV, jni_CallNonvirtualCharMethodA,
jni_CallNonvirtualShortMethod, jni_CallNonvirtualShortMethodV,
jni_CallNonvirtualShortMethodA, jni_CallNonvirtualIntMethod,
jni_CallNonvirtualIntMethodV, jni_CallNonvirtualIntMethodA,
jni_CallNonvirtualLongMethod, jni_CallNonvirtualLongMethodV,
jni_CallNonvirtualLongMethodA, jni_CallNonvirtualFloatMethod,
jni_CallNonvirtualFloatMethodV, jni_CallNonvirtualFloatMethodA,
jni_CallNonvirtualDoubleMethod, jni_CallNonvirtualDoubleMethodV,
jni_CallNonvirtualDoubleMethodA, jni_CallNonvirtualVoidMethod,
jni_CallNonvirtualVoidMethodV, jni_CallNonvirtualVoidMethodA,
jni_GetFieldID,
jni_GetObjectField, jni_GetBooleanField, jni_GetByteField, jni_GetCharField,
jni_GetShortField, jni_GetIntField, jni_GetLongField, jni_GetFloatField,
jni_GetDoubleField,
jni_SetObjectField, jni_SetBooleanField, jni_SetByteField, jni_SetCharField,
jni_SetShortField, jni_SetIntField, jni_SetLongField, jni_SetFloatField,
jni_SetDoubleField,
jni_GetStaticMethodID,
jni_CallStaticObjectMethod, jni_CallStaticObjectMethodV, jni_CallStaticObjectMethodA,
jni_CallStaticBooleanMethod, jni_CallStaticBooleanMethodV, jni_CallStaticBooleanMethodA,
jni_CallStaticByteMethod, jni_CallStaticByteMethodV, jni_CallStaticByteMethodA,
jni_CallStaticCharMethod, jni_CallStaticCharMethodV, jni_CallStaticCharMethodA,
jni_CallStaticShortMethod, jni_CallStaticShortMethodV, jni_CallStaticShortMethodA,
jni_CallStaticIntMethod, jni_CallStaticIntMethodV, jni_CallStaticIntMethodA,
jni_CallStaticLongMethod, jni_CallStaticLongMethodV, jni_CallStaticLongMethodA,
jni_CallStaticFloatMethod, jni_CallStaticFloatMethodV, jni_CallStaticFloatMethodA,
jni_CallStaticDoubleMethod, jni_CallStaticDoubleMethodV, jni_CallStaticDoubleMethodA,
jni_CallStaticVoidMethod, jni_CallStaticVoidMethodV, jni_CallStaticVoidMethodA,
jni_GetStaticFieldID,
jni_GetStaticObjectField, jni_GetStaticBooleanField, jni_GetStaticByteField,
jni_GetStaticCharField, jni_GetStaticShortField, jni_GetStaticIntField,
jni_GetStaticLongField, jni_GetStaticFloatField, jni_GetStaticDoubleField,
jni_SetStaticObjectField, jni_SetStaticBooleanField, jni_SetStaticByteField,
jni_SetStaticCharField, jni_SetStaticShortField, jni_SetStaticIntField,
jni_SetStaticLongField, jni_SetStaticFloatField, jni_SetStaticDoubleField,
jni_NewString, jni_GetStringLength, jni_GetStringChars, jni_ReleaseStringChars,
jni_NewStringUTF, jni_GetStringUTFLength,
jni_GetStringUTFChars, jni_ReleaseStringUTFChars,
jni_GetArrayLength,
jni_NewObjectArray, jni_GetObjectArrayElement, jni_SetObjectArrayElement,
jni_NewBooleanArray, jni_NewByteArray, jni_NewCharArray, jni_NewShortArray,
jni_NewIntArray, jni_NewLongArray, jni_NewFloatArray, jni_NewDoubleArray,
jni_GetBooleanArrayElements, jni_GetByteArrayElements, jni_GetCharArrayElements,
jni_GetShortArrayElements, jni_GetIntArrayElements, jni_GetLongArrayElements,
jni_GetFloatArrayElements, jni_GetDoubleArrayElements,
jni_ReleaseBooleanArrayElements, jni_ReleaseByteArrayElements,
jni_ReleaseCharArrayElements, jni_ReleaseShortArrayElements,
jni_ReleaseIntArrayElements, jni_ReleaseLongArrayElements,
jni_ReleaseFloatArrayElements, jni_ReleaseDoubleArrayElements,
jni_GetBooleanArrayRegion, jni_GetByteArrayRegion, jni_GetCharArrayRegion,
jni_GetShortArrayRegion, jni_GetIntArrayRegion, jni_GetLongArrayRegion,
jni_GetFloatArrayRegion, jni_GetDoubleArrayRegion,
jni_SetBooleanArrayRegion, jni_SetByteArrayRegion, jni_SetCharArrayRegion,
jni_SetShortArrayRegion, jni_SetIntArrayRegion, jni_SetLongArrayRegion,
jni_SetFloatArrayRegion, jni_SetDoubleArrayRegion,
jni_RegisterNatives, jni_UnregisterNatives,
jni_MonitorEnter, jni_MonitorExit,
jni_GetJavaVM,
jni_GetStringRegion, jni_GetStringUTFRegion,
jni_GetPrimitiveArrayCritical, jni_ReleasePrimitiveArrayCritical,
jni_GetStringCritical, jni_ReleaseStringCritical,
jni_NewWeakGlobalRef, jni_DeleteWeakGlobalRef,
jni_ExceptionCheck,
jni_NewDirectByteBuffer, jni_GetDirectBufferAddress, jni_GetDirectBufferCapacity,
// New 1_6 features
jni_GetObjectRefType
};
4、InvocationFunctions
见:/src/share/tools/luancher/java.h

InvocationFunctions中包含了2个函数指针,CreateJavaVM和GetDefaultJavaVMInitArgs,这2个函数将在LoadJavaVM时指定函数定义。在/src/os/posix/launcher/java_md.c中定义了LoadJavaVM函数,函数执行中对2个函数指针进行了指定,如下:

值得注意的是,也正是在LoadJavaVM中,release版本的hotspot在此处会载入libjvm。

那么,JNI_CreateJavaVM和JNI_GetDefaultJavaVMInitArgs在什么时候调用呢?其具体做了哪些事呢?JNI_GetDefaultJavaVMInitArgs的调用要先于CreateJavaVM。
介绍到这里,我们再返回本节的主题:InitializeJVM做了哪些事情?答案就很明了了:调用已准备好的CreateJavaVM函数,即:JNI_CreateJavaVM。通过调用该函数,完成虚拟机的创建。
另外,InitializeJVM中也会打印参数,我们不妨来看看打印了哪些信息:
可见JavaVM args,打印了一些version和JVM参数等信息。
三、HelloWorld的main方法的调用
在JavaMain()中,初始化虚拟机后,将准备调用main class的main method。在上一篇中我们知道,通过env已准备好的函数指针CallStaticVoidMethod,去调用一个static void的方法,即java主程序的main方法。
函数指针变量CallStaticVoidMethod实际指向函数jni_CallStaticVoidMethod,该函数定义在jni.h中:

实际运行时,见jni.cpp:

显然,main方法的调用,与普通的static方法调用,并没有特别对待,仍然是通过jni_invoke_static。jni_invoke_static将通过调用JavaCalls::call()完成指定method的执行。
