zoukankan      html  css  js  c++  java
  • java JNI 实现原理 (二) Linux 下如何 load JNILibrary

    在博客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方法,并且运行方法,对我们来说从而实现可以自定义的初始化方法。

  • 相关阅读:
    Spark函数详解系列之RDD基本转换
    Spark算子之aggregateByKey详解
    基于Apache Spark机器学习的客户流失预测
    Spark partitionBy
    Spark中repartition和partitionBy的区别
    Spark快速获得CrossValidator的最佳模型参数
    Spark MLlib之水塘抽样算法(Reservoir Sampling)
    机器学习-加权采样算法简介
    基于Spark的大数据精准营销中搜狗搜索引擎的用户画像挖掘(转)
    Mark 装修建材 清单
  • 原文地址:https://www.cnblogs.com/yelao/p/9592315.html
Copyright © 2011-2022 走看看