java qt jni_java JNI 实现原理 (二) Linux 下如何 load JNILibrary
在博客java JNI (一)
虛擬機中classloader的JNILibrary 中討論了java中的Library 是由classloader 來load的,那我們來看看 classloader是如何去load 一個library的。
ClassLoader.c
[cpp]
JNIEXPORT voidJNICALL
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;inti;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);gotodone;
}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);gotodone;
}
(*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);
}gotodone;
}
(*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);returnres;
}
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) returnJNI_TRUE;if (version == JNI_VERSION_1_4) returnJNI_TRUE;if (version == JNI_VERSION_1_6) returnJNI_TRUE;returnJNI_FALSE;
}
完整的加載過程就是
首先先加載動態鏈接庫,嘗試查找JNI_OnLoad方法,并且運行方法,對我們來說從而實現可以自定義的初始化方法。
總結
以上是生活随笔為你收集整理的java qt jni_java JNI 实现原理 (二) Linux 下如何 load JNILibrary的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java兩個矩陣相乘_Day12 練習
- 下一篇: php 百度收录api_php使用百度翻