首先来看一下C/C++中的引用
从Java虚拟机创建的对象传到本地C/C++代码时会产生引用,根据Java的垃圾回收机制,只要有引用存在就不会触发该引用指向的Java对象的垃圾回收
第一、局部引用:
最常见的引用类型,基本上通过JNI返回来的引用都是局部引用,例如使用NewObject就会返回创建出来的实例的局部引用,局部引用只在该native函数中有效,所有在该函数中产生的局部引用,都会在函数返回的时候自动释放,也可以使用DeleteLocalRef函数手动释放该引用
想一想既然局部引用能够在函数返回时自动释放,为什么还需要DeleteLocalRef函数呢
实际上局部引用存在,就会防止其指向的对象被垃圾回收,尤其是当一个局部引用指向一个很庞大的对象,或是在一个循环中生成了局部引用,最好的做法就是在使用完该对象后,活在该循环尾部把这个引用释放掉,以确保在垃圾回收器被触发的时候被回收
在局部引用的有效期中,可以传递到别的本地函数中,要强调的是他的有效期任然只在一次的Java本地函数调用中,所以千万不能用C++全局变量保存他或是把他定义为C++静态局部变量
第二、全局引用
全局引用可以跨越当前线程,在多个native函数中有效,不过需要编程人员手动来释放该引用,全局引用存在期间会防止在Java的垃圾回收器的回收
与局部引用不同,全局引用的创建不是由JNI自动创建的,全局引用是需要调用NewGlobalRef函数,而释放他需要使用ReleaseGlobalRef函数
弱全局引用
Java1.2新出来的功能,与全局引用相似,创建和删除都需要由编程人员来进行,这种引用与全局引用一样可以在多个本地代码中有效,也跨越多线程有效,不一样的是,这种引用将不会阻止垃圾回收器回收这个引用所指向的对象
使用NewWeakGlobalRef和ReleaseWeakGlobalRef来产生和解除引用
关于引用的一个函数:
jobject NewGlobalRef(jobject obj);
jobject NewLocalRef(jobject obj);
jobject new WeakGlobalRef(jobject obj);
void DeleteGobalRef(jobject obj);
void DeleteLocalRef(jobject obj);
void DeleteWeakGlobalRef(jobject obj);
上述的六种方法很好理解的,这里就不做揭示了
jboolean IsSameObject(jobject obj1 , jobject obj2);
这个函数就是用来比较两个引用是否相等,但是对于弱全局引用还有一个特别的功能,如果把NULL传入要比较的对象中,就能够判断弱全局引用所指向的Java对象是否被回收
缓存jfieldID/jmethodID
取得jfieldID和jmethodID的时候会通过该属性/方法名称加上签名来查询相应的jfieldID/jmethodID.这种查询相对于来说开销大,我们可以将这些FieldID/MethodID缓存起来,这样就需要查询一次,以后就是用缓存起来的FieldID/MethodID了
下面介绍两种缓存方法是:
1.在用的时候缓存
在native code 中使用static 局部变量来保存已经查询过的id,这样就不会在每次的函数调用时查询,而只要第一次查询成功后就保存起来了
不过在这种情况下就不得不考虑多线程同时呼叫此函数时可能会招致同时查询的危机,不过这种情况是无害的,因为查询同一个属性/方法的ID通常返回的是一样的值
在static jfieldID fieldID_string = NULL;这段代码只执行一次
2.在Java类初始化时缓存
更好的一个方式就是在任何native函数调用前把id全部存起来
我们可以让Java在第一次加载这个类的时候首先调用本地代码初始化所有的jfieldID/jmethodID,这样的话就可以省去多次的确定id是否存在的语句,当然,这些jfieldID/jmethodID是定义在C/C++的全局
使用这种方式还有好处,当Java类卸载或是从新加载的时候,也会重新呼叫该本地代码来从新计算IDs
在Java中使用静态代码块中进行初始化
使用JNI中的两个弊端:
1.使用了JNI,那么这个Java Application将不能跨平台了,如果要移植到别的平台上,那么native代码就需要从新进行编写
2. Java是强类型语言,而C/C++不是,因此,你必须在写JNI的时候更加小心
介绍两本资料:
The Java Native Interface Programmer's Guide and Specification
JNI++ User Guide
关于JNI的学习到此结束!
分享到:
相关推荐
JNI开发Java和C/C++互相传递List集合, 可以参考: Java从C/C++获取List集合对象:https://blog.csdn.net/niuba123456/article/details/80994166 Java传递List集合对象到C/C++ ...
JNI实现java cpp相互调用...Java中访问C/C++方法 Java中访问/修改C/C++变量 动态方式实现: C/C++中访问Java方法 C/C++中访问Java父类的方法 C/C++中访问/修改Java变量 Java中访问C/C++方法 Java中访问/修改C/C++变量
NULL 博文链接:https://conkeyn.iteye.com/blog/1597188
使用C/C++实现Java的Native方法接口(JNI)/ JNI编程(C/C++) 代码实例
java 调用 dll 的方法,即JNI的使用,demo中有get()/set()方法,操作步骤详细,即使是没用过java的程序员按照步骤依然可以成功。
Android JNI/NDK开发(2)JNI实现C/C++与Android/JAVA相互调用 http://blog.csdn.net/u014702653/article/details/71141423
利用JNI技术实现Java中调用C++编写的函数库示例程序源码,并附上参考JNI文档。 详情见本人博客:Java学习之通过JNI调用C/C++编写的dll链接库(图文教程)(http://write.blog.csdn.net/postlist)
通过jni完成java调用c/c++,包含c/c++生成Dll动态库
II. java c/cpp互相调用实例(姊妹篇之一)——java调用c/cpp 4 一 先制作一个系统中有的DLL文件(cpp给出的sdk接口) 4 二 JNI 7 1、 编写java文件 7 2、 生成.h头文件 8 3、 用c/cpp实现这个头文件 9 三 测试 10 ...
NDK开发时,C/C++调用Java的函数的一些案例; 传递int类型参数: https://blog.csdn.net/niuba123456/article/details/80978500 传递String类型参数: https://blog.csdn.net/niuba123456/article/details/80978916 ...
cocos2d-x 通过JNI实现c/c++和Android的java层函数互调-源码 详情请移步到:http://codingnow.cn/program/992.html
android C/C++ JNI普通数据类型 测试工程, 最好配合文章看《Android JNI C/C++编程--数据类型》
在VS2013中使用JNI进行JAVA和C++之间的互调,这两个文件只是项目中的一部分,仅供参考
NULL 博文链接:https://wuneng94zui.iteye.com/blog/1218725
Android Studio 通过JNI机制和 ndk开发的C/C++沟通的具体步骤 (以图像模糊化为例) 文章地址:http://blog.csdn.net/kpioneer123/article/details/51097239
我们知道,在C层有*.SO,它有全局变量,不要将Java或C++对象参考储存于C层的全局变量,把动态的对象指针放在全局变量是不好的。这样可以增加C函数的稳定度,包括它的通用性,可适应于更多更多的环境里使用,表示它...
http://blog.csdn.net/csdn49532/article/details/50624627 配套代码,使用JAVA和JNI二种方法动态加载dex,调用dex中的方法,对android APK进行加固,防止APK被破解。
即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码。由于JNI是JVM规范的一部分,因此可以将我们写的JNI的程序在任何实现了JNI规范的Java虚拟机中运行。同时,这个特性使我们可以复用以前用C/...
即可以在Java代码中调用C/C++等语言的代码或者在C/C++代码中调用Java代码。由于JNI是JVM规范的一部分,因此可以将我们写的JNI的程序在任何实现了JNI规范的Java虚拟机中运行。同时,这个特性使我们可以复用以前用C/...
cocos2d-x 通过JNI实现c/c++和Android的java层函数互调, 本文主要实现两个功能: (1)通过Android sdk的API得到应用程序的包名(PackageName),然后传递给c++层函数。 (2)通过c++函数调用Android的java层函数,显示一...