JNI详解

2021-03-05  本文已影响0人  ZY如幻

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

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
上一篇下一篇

猜你喜欢

热点阅读