標籤:ring 虛擬機器 tps style ptr 也會 form require read
在部落格java JNI (一)虛擬機器中classloader的JNILibrary 中討論了java中的Library 是由classloader 來load的,那我們來看看 classloader是如何去load 一個library的。
ClassLoader.c
[cpp]
JNIEXPORT void JNICALL Java_java_lang_ClassLoader_00024NativeLibrary_load (JNIEnv *env, jobject this, jstring name) { const char *cname; jint jniVersion; jthrowable cause; void * handle; if (!initIDs(env)) return; cname = JNU_GetStringPlatformChars(env, name, 0); if (cname == 0) return; handle = JVM_LoadLibrary(cname); if (handle) { const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; JNI_OnLoad_t JNI_OnLoad; int i; for (i = 0; i < sizeof(onLoadSymbols) / sizeof(char *); i++) { JNI_OnLoad = (JNI_OnLoad_t) JVM_FindLibraryEntry(handle, onLoadSymbols[i]); if (JNI_OnLoad) { break; } } if (JNI_OnLoad) { JavaVM *jvm; (*env)->GetJavaVM(env, &jvm); jniVersion = (*JNI_OnLoad)(jvm, NULL); } else { jniVersion = 0x00010001; } cause = (*env)->ExceptionOccurred(env); if (cause) { (*env)->ExceptionClear(env); (*env)->Throw(env, cause); JVM_UnloadLibrary(handle); goto done; } if (!JVM_IsSupportedJNIVersion(jniVersion)) { char msg[256]; jio_snprintf(msg, sizeof(msg), "unsupported JNI version 0x%08X required by %s", jniVersion, cname); JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); JVM_UnloadLibrary(handle); goto done; } (*env)->SetIntField(env, this, jniVersionID, jniVersion); } else { cause = (*env)->ExceptionOccurred(env); if (cause) { (*env)->ExceptionClear(env); (*env)->SetLongField(env, this, handleID, (jlong)NULL); (*env)->Throw(env, cause); } goto done; } (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle)); done: JNU_ReleaseStringPlatformChars(env, name, cname); }
1. JVM_LoadLibrary
jvm中load library 核心函數,實現也非常簡單,在linux下調用了系統函數dlopen去開啟庫檔案,詳細可參考方法
[cpp]
void * os::dll_load(const char *filename, char *ebuf, int ebuflen)
2. JVM_FindLibraryEntry
JVM在載入庫檔案時候,會去嘗試尋找庫中的JNI_ONLOAD方法的地址,而在Linux中調用了dlsym函數通過前面的dlopen載入庫的指標去擷取方法的地址,而dlsym在glibc2.0是非安全執行緒的,需要鎖的保護,雖然在java中載入庫已經有鎖的保護,但只是針對同一個classloader對象的細部鎖定。
[cpp]
void* os::dll_lookup(void* handle, const char* name) { pthread_mutex_lock(&dl_mutex); void* res = dlsym(handle, name); pthread_mutex_unlock(&dl_mutex); return res; }
3. 方法JNI_OnLoad
JVM提供了一種方式允許你在載入庫檔案的時候做一些你想做的事情,也就是JNI_OnLoad方法
在2中提到過在載入動態連結程式庫,JVM會去嘗試尋找JNI_OnLoad方法,同時也會調用該函數,這樣你個人可以在函數裡做一些初始化的事情,比如register native方法。
[cpp]
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {}
JNI_OnLoad中返回的是JNI 的version,在1.6版本的情況下支援如下
[cpp]
jboolean Threads::is_supported_jni_version(jint version) { if (version == JNI_VERSION_1_2) return JNI_TRUE; if (version == JNI_VERSION_1_4) return JNI_TRUE; if (version == JNI_VERSION_1_6) return JNI_TRUE; return JNI_FALSE; }
完整的載入過程就是
首先先載入動態連結程式庫,嘗試尋找JNI_OnLoad方法,並且運行方法,對我們來說從而實現可以自訂的初始化方法。
java JNI 實現原理 (二) Linux 下如何 load JNILibrary