java JNI 實現原理 (二) Linux 下如何 load JNILibrary

來源:互聯網
上載者:User

標籤: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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.