javajni实现原理linux下如何loadjnilibrary

i野老i      2022-04-11     204

关键词:

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

 

 

javajni怎么在windows环境中编译成linux下的so文件

可以直接在android工程下使用,因为android就是linux内核。android的NDK开发需要在linux下进行:因为需要把C/C++编写的代码生成能在arm上运行的.so文件,这就需要用到交叉编译环境,而交叉编译需要在linux系统下才能完成。2.安装android-... 查看详情

如何在linux下使用tc优雅的实现网络限流

1.Linux下的流量控制原理通过对包的排队,我们可以控制数据包的发送方式。这种控制,称之为数据整形,shapethedata,包括对数据的以下操作:增加延时丢包重新排列重复、损坏速率控制在qdisc-class-filter结构下,对流量进行控制需... 查看详情

javajni实现调用自定义native方法(代码片段)

JNI是JavaNativeInterface的缩写,通过使用Java本地接口书写程序,可以确保代码在不同的平台上方便移植。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互目录一、前言二、准... 查看详情

linux下实现断点续传的原理介绍

参考技术A  Linux下实现断点续传的原理介绍  断点续传的原理  其实断点续传的原理很简单,就是在Http的请求上和一般的下载有所不同而已。  打个比方,浏览器请求服务器上的一个文时,所发出的请求如下:  假... 查看详情

mysql原理篇之索引是如何一步步实现的---下--03(代码片段)

Mysql原理篇之索引是如何一步步实现的---下--03Innodb如何实现索引B+树聚簇索引二级索引联合索引InnoDB的B+树索引的注意事项根页面万年不动窝内节点中目录项记录的唯一性一个页面最少存储2条记录MyISAM中的索引方案简单介... 查看详情

javajni调用c代码,c中unsignedchar*数据如何传给java?

C:unsignedchar*---无符号型字符数组。java需要使用c中的unsignedchar*应该怎么做比较好?unsignedchar*如何转换传给java?参考技术A(*env)->NewStringUTF(env,"HellofromJNI!");new一个java的string本回答被提问者采纳 查看详情

[java]如何在windows下读取远程的linux下面的文件?

....请问如何在windows下读取到远程的linux文件呢?而且是用java实现我想要知道的是原理,比如异构系统下的信息交互需要什么条件吗?java中如何和远程的异构系统间创建流对象?说的越详细越好,说的好的我追分!补充一下,要读取的文件... 查看详情

pf_netlink应用实例netlink_kobject_uevent具体实现--udev实现原理

PF_NETLINK应用实例NETLINK_KOBJECT_UEVENT具体实现--udev实现原理相对于linux来说,udev还是一个新事物。然而,尽管它03年才出现,尽管它很低调(J),但它无疑已经成为linux下不可或缺的组件了。udev是什么?它是如何实现的?最近研究L... 查看详情

altiumdesigner16如何实现选中pcb器件后原理图高亮显示?

AD软件有这项功能吗?在PCB中选中器件或者连线,然后原理图高亮显示出来?参考技术A这个功能应该一直都有的,只要原理图跟PCB是同步的,那么在PCB编辑器界面下选中某个器件,切到原理图编辑器界面下会看到对应的原理图符... 查看详情

linux|mmap的实现原理和应用(代码片段)

概述对于mmap,您是否能从原理上解析以下三个问题:mmap比物理内存+swap空间大情况下,是否有问题?MAP_SHARED,MAP_PRIVATE,MAP_ANONYMOUS,MAP_NORESERVE到底有什么区别?常听说mmap的读写比传统的系统调用(rea... 查看详情

linux下如何编程实现获取显卡的状态?

.../dev/下相关文件的状态,另一种方式是通过BIOS读取。具体实现,你可以进一步查找相关资料 参考技术B比较有难度的问题,等待大神 查看详情

linux系统下如何实现文件系统配额

1.配额又称为限额,针对的是分区,不是用户也不是文件,更不是整个硬盘;2.内核版本必须是2.4以上才支持;查看内核是否支持配额。3.root是不受配额限制的,只有普通用户才受限制;4.配额中的术语:<1>软限制:警告限制... 查看详情

shell的运行原理以及linux当中的权限问题

...录Shell的运行原理Linux当中的权限问题Linux权限的概念如何实现用户账号之间的切换如何仅提升当前指令的权限如何将普通用户添加到信任列表Linux权限管理文件访问者的分类(人)文件类型和访问权限(事物属性)... 查看详情

tcpdump实现原理整理

参考:http://blog.sina.com.cn/s/blog_523491650101au7f.html 一、tcpdump对于本机中进程的系统行为调用跟踪,strace是一个很好的工具,而在网络问题的调试中,tcpdump应该说是一个必不可少的工具,和大部分linux下优秀工具一样,它的特点... 查看详情

linux下,采用消息队列实现进程通信(待续)

...,消息队列不一定是先进先出了。 这次我用消息队列实现一个简单的进程间通信程序,让两个进程server和client进行通信 (由于要准备学校的期末考试,先贴代码和运行结果,原理分析之后补上) 程序结构: 650)th... 查看详情

linux下进程结束时如何得到通知?

...进程结束,我想运行一些代码。我找到了几个使用轮询来实现此目的的示例,但我正在寻找一种在进程终止时被推送(可能由操作系统)的方法。这可以用C或C++实现吗?它应该可以在任何现代Linux上运行。如果有任何机会,我想 查看详情

在linux下如何利用c语言实现http的get和post方法?

在LINUX下如何利用C语言实现HTTP的get和post方法?我是远程登录的LINUX,在LINUX下用Eclipse开发有关HTTP解析,不会实现HTTP的get和post方法,有没有高手指点一下啊?不要网上拉的网址和内容最好是程序实例!要求只要能给服务器发数... 查看详情

js原生方法原理探究:如何实现instanceof?

...JS原生方法原理探究系列的第五篇文章。本文会介绍如何实现instanceof方法。typeof操作符返回一个表示数据类型的字符串,它可以应付常规场景下的数据类型判断。对基本数据类型undefined、boolean、string、number、Symbol和引用数据类... 查看详情