JNI详解

作者: ZY如幻 | 来源:发表于2021-03-05 11:03 被阅读0次

        一切诸法性皆如是,唯是自心分别境界。凡夫迷惑不能解了,无有能见亦无所见,无有能说亦无所说,见佛闻法皆是分别,如向所说不能见佛,不起分别是则能见。            ----------佛说

    JNI编程

    JNI是一种本地编程接口。它允许运行在JAVA虚拟机中的JAVA代码和用其他编程语言,诸如C语言、C++、汇编,写的应用和库之间的交互操作。

    JNI数据类型

    JNIEXPORT 和 JNICALL,定义在`jni_md.h`头文件中。

    JNIEXPORT:

        在 Windows 中,定义为`__declspec(dllexport)`。因为Windows编译 dll 动态库规定,如果动态库中的函数要被外部调用,需要在函数声明中添加此标识,表示将该函数导出在外部可以调用。

    在 Linux/Unix/Mac os/Android 这种 Like Unix系统中,定义为`__attribute__ ((visibility ("default")))`GCC 有个visibility属性, 该属性是说, 启用这个属性:

    1. 当-fvisibility=hidden时动态库中的函数默认是被隐藏的即 hidden. 除非显示声明为`__attribute__((visibility("default")))`.

    2 当-fvisibility=default时动态库中的函数默认是可见的.除非显示声明为`__attribute__((visibility("hidden")))`.

    JNICALL:

    在类Unix中无定义,在Windows中定义为:`_stdcall  ` ,一种函数调用约定 。类Unix系统中这两个宏可以省略不加

    图1

    C/C++中获取java的数组

    图二

    C/C++反射Java

    1在C/C++中反射创建Java的对象,调用Java的方法

    图三 图四

    基本数据类型的签名采用一系列大写字母来表示, 如下表所示:

    图5

    可以使用javap来获取反射方法时的签名

            cd 进入 class所在的目录 执行: javap -s 全限定名,查看输出的 descriptor

    图6


    反射属性

    图7 图10


    JNI引用

    在 JNI 规范中定义了三种引用:局部引用(Local Reference)、全局引用(Global Reference)、弱全局引用(Weak Global Reference)。

        局部引用

       大多数JNI函数会创建局部引用。NewObject/FindClass/NewStringUTF 等等都是局部引用。

         局部引用只有在创建它的本地方法返回前有效,本地方法返回后,局部引用会被自动释放。

        因此无法跨线程、跨方法使用。

    图11

    释放一个局部引用有两种方式:

    1、本地方法执行完毕后VM自动释放;  2、通过DeleteLocalRef手动释放;

    VM会自动释放局部引用,为什么还需要手动释放呢?因为局部引用会阻止它所引用的对象被GC回收。

    全局引用

     全局引用可以跨方法、跨线程使用,直到它被手动释放才会失效 。

    由 NewGlobalRef 函数创建

    图12

    弱引用

    与全局引用类似,弱引用可以跨方法、线程使用。与全局引用不同的是,弱引用不会阻止GC回收它所指向的VM内部的对象 。

    在对Class进行弱引用是非常合适(FindClass),因为Class一般直到程序进程结束才会卸载。

    在使用弱引用时,必须先检查缓存过的弱引用是指向活动的对象,还是指向一个已经被GC的对象

    图13

    JNI_OnLoad函数

    调用System.loadLibrary()函数时, 内部就会去查找so中的 JNI_OnLoad 函数,如果存在此函数则调用。

    JNI_OnLoad会:

    告诉 VM 此 native 组件使用的 JNI 版本。

    对应了Java版本,android中只支持JNI_VERSION_1_2 、JNI_VERSION_1_4、JNI_VERSION_1_6

    在JDK1.8有 JNI_VERSION_1_8。

    图14


    动态注册

    1 在此之前我们一直在jni中使用的 Java_PACKAGENAME_CLASSNAME_METHODNAME 来进行与java方法的匹配,这种方式我们称之为静态注册。

    2 而动态注册则意味着方法名可以不用这么长了,在android aosp源码中就大量的使用了动态注册的形式

    图15 图16


    native跨线程调用Java

             native调用java需要使用JNIEnv这个结构体,而JNIEnv是由Jvm传入与线程相关的变量。

              但是可以通过JavaVM的AttachCurrentThread方法来获取到当前线程中的JNIEnv指针。 

    图16 图16 图16

    相关文章

      网友评论

          本文标题:JNI详解

          本文链接:https://www.haomeiwen.com/subject/jfcrqltx.html