Android jni/ndk编程四:jni引用类型
一.JNI引用类型
JNI支持三种类型的 opaque reference:local references, global references,和weak global references,下面我们将逐一探讨。
local references
大部分JNI 函数都会创建LocalRef,如NewObject创建一个实例,并返回一个指向该实例的LocalRef。LocalRef只在本线程的 native method中有效. 一但native method返回,LocalRef 将被释放。这意味着我们不能缓存LocalRef来提高效率,因为native方法一旦返回,LocalRef将被释放,缓存起来也没有用。
我们已经知道了大部分JNI函数都会创建LocalRef,比如NewObject,FindClass等,与创建相对应的,我们可以有两种方式让LocalRef 无效:
- native method返回,JavaVM自动释放LocalRef;
- 用DeleteLocalRef 主动释放。
DeleteLocalRef的定义如下:
void (*DeleteLocalRef)(JNIEnv*, jobject);
DeleteLocalRef 主动释放LocalRef是有意义的,如果我们内存特别紧张,而一个本地的方法有很多很耗内存的LocalRef,这个时候,在本地方法中及时释放这些LocalRef可以缓解内存压力。
LocalRef只在创建该对象的线程中有效,因此我们无法在其他线程中使用共享LocalRef.
Global References
Global引用类似于全局变量,我们可以在多个native方法中使用,也可以在多个线程中使用。此外,Golbal引用会阻止GC回收。但是,与c总的全局变量不同的是,Golbal引用必须通过特定的函数手动创建和释放。以下是相关函数的定义:
jobject (*NewGlobalRef)(JNIEnv*, jobject);
void (*DeleteGlobalRef)(JNIEnv*, jobject);
使用举例:
//1.首先定义一个静态变量存储Global引用
static jclass stringClass = NULL;
//2.获得Local 引用
jclass localRefCls = (*env)->FindClass(env,
"java/lang/String");
if (localRefCls == NULL) {
return NULL; /* exception thrown */
}
//3.使用那个local引用创建全局引用
stringClass = (*env)->NewGlobalRef(env, localRefCls);
//4.及时释放Local引用
(*env)->DeleteLocalRef(env, localRefCls);
以上是常见的、简单的创建Global引用的代码流程,使用完以后,记得把它释放掉,不然后内存泄漏了,因为Global引用是阻止GC的。
Weak Global References
所谓弱全局引用就是全局引用的另一个版本,既然它是全局引用,那么它就具备了在多个线程中共享的能力,以及我们可以在单个线程的不同函数中都可以使用它。之所以说它弱是因为它无法阻止GC。前面我们说Global引用很强势,它只能手动释放,JVM虚拟机不能自动GC它,但是Weak Global就会被垃圾回收器回收,这就是它若的原因。
Weak Global Ref用 NewGlobalWeakRef于DeleteGlobalWeakRef进行创建和删除,多个本地方法调用过程中和多线程上下文中使用的特性与 GlobalRef相同。这两个函数在jni.h中的定义如下:
jweak (*NewWeakGlobalRef)(JNIEnv*, jobject);
void (*DeleteWeakGlobalRef)(JNIEnv*, jweak);
我们看到这里又出现了一个新的类型:jweak,它其实就是jobject,只是名字不容而已:
typedef jobject jweak;
用法举例:
static jclass string= NULL;
if (string == NULL) {
jclass local_string =
(*env)->FindClass(env, "java/lang/String");
if (myCls2Local == NULL) {
return; /* can’t find class */
}
string = NewWeakGlobalRef(env, local_string );
if (myCls2 == NULL) {
return; /* out of memory */
}
}
由于Weak Global引用可能被垃圾回收器回收,所以我们在使用它之前一定要判断它是否为空。如果空的话需要重新创建它,不为空就继续使用。
二.Comparing Reference
既然我们可以有多个引用,它可能是全局引用,弱全局引用或局部引用,我们怎么判断它是不是同一个引用呢?不用急,JNI已经为我们提供好了函数,我们可以直接用,其定义如下:
jboolean (*IsSameObject)(JNIEnv*, jobject, jobject);
如果相通,返回JNI_TRUE, 否则返回JNI_FALSE。
三.引用管理
引用管理是为了较少内存使用,提高代码效率。JNI支持的三种引用各有各得用途,绝不能滥用。笔者水平有限,就不多废话了,这里主要讲一下Local引用的管理。
JNI提供了一组管理Local引用的函数:
jint (*PushLocalFrame)(JNIEnv*, jint);
jobject (*PopLocalFrame)(JNIEnv*, jobject);
在进入本地方法时,调用一次
PushLocalFrame,并在本地方法结束时调用 PopLocalFrame. 此对方法执行效率非常高,建议使用这对方法。
一定保证该上下文出口只有一个,或每个return语句都做严格检查是否调用了PopLocalFrame。因为如果忘记调用PopLocalFrame 可能会使JVM崩溃。
用法举例:
jobject hello(JNIEnv *env, jobject obj)
{
jobject result;
//进入函数后push
if ((*env)->PushLocalFrame(env, 10) < 0) {
/* frame not pushed, no PopLocalFrame needed */
return NULL;
}
...
result = ...;
if (...) {
//认真检查每一个函数的出口,绝不能忘记PopLocalFrame
result = (*env)->PopLocalFrame(env, result);
return result;
}
...
//正常返回前pop一下
result = (*env)->PopLocalFrame(env, result);
return result;
}
Android jni/ndk编程四:jni引用类型的更多相关文章
- Android之NDK编程(JNI)
转自:http://www.cnblogs.com/xw022/archive/2011/08/18/2144621.html NDK编程入门--C回调JAVA方法 一.主要流程 1. 新建一个 ...
- Delphi使用android的NDK是通过JNI接口,封装好了,不用自己写本地代码,直接调用
一.Android平台编程方式: 1.基于Android SDK进行开发的第三方应用都必须使用Java语言(Android的SDK基于Java实现) 2.自从ndk r5发布以后, ...
- Android Studio NDK编程初探
继上一篇学习了如何使用NDK编译FFMPEG后,接下来就是要学习如何在Android Studio中使用了. 经过参考和一系列的摸索,记录下具体步骤. 创建C++ Support的Android St ...
- Android JNI&NDK编程小结及建议
前言 由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签 ...
- Android jni/ndk编程二:jni数据类型转换(primitive,String,array)
一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把 ...
- Android jni/ndk编程五:jni异常处理
在Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常.处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常.那么在jn ...
- Android之NDK环境配置+JNI开发+so文件编译
前言 这边Android作为日常记录,虽然破坏了文章队形~ 最近人工智能挺火的,也稍微了解了一些库,比如关于视觉库openCV.要在安卓下调用这些C/C++库,需要用到JNI开发,在此把过程分享一 ...
- Android Studio Ndk 编程
如今开发Android程序基本都已经从Eclipse转到了Android Studio了, 近期项目需求, 须要用到ndk编程, 于是就折腾了一下. 开发环境 Android Studio 1.5.1 ...
- Android Studio JNI/NDK 编程简介(一)
首先说一下概念及相关的东西: JNI : JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++).从Java1.1开始 ...
随机推荐
- 3.Struts2-Result
注: 1.在struts.xml文件中使用include标签 可以将另外一个xml文件包含进struts.xml文件中,如: <struts> <constant name=&quo ...
- SpringBoot整合MongoDB JPA,测试MongoRepository与MongoTemplate用法,简单增删改查+高级聚合
源码 地址 -> https://github.com/TaoPanfeng/case/tree/master/04-mongo/springboot-mongo 一 引入依赖 <depe ...
- bizcharts在火狐上的Invalid date报错
bizcharts在火狐上的Invalid date报错,是因为 bizcharts 所用到的 fecha在 火狐上 只能接收日期对象类型的日期,不能接收日期字符串.
- Java并发与多线程
1. 并发与并行 并发是指某个时间段内,多任务交替处理的能力:并行是指同时处理多任务的能力,多核CPU可以实现并行任务. 并发执行的特点: (1)并发程序间相互制约:程序执行结果的相互依赖以及共享资源 ...
- python list按字典的key值排序
方法1: result_list = sorted(origin_list, key=lambda e: e.__getitem__('order_key')) 方法2: import operato ...
- Redis日志级别
Redis默认的设置为verbose,开发测试阶段可以用debug,生产模式一般选用notice 1. debug:会打印出很多信息,适用于开发和测试阶段 2. verbose(冗长的):包含很多不太 ...
- 重新编译mysqldump,使mysqldump具有进度输出功能
重新编译mysql,使mysqldump具有进度输出功能 安装编译过程所必须的依赖包和环境 yum install -y gcc cmake boost boost-build boost-devel ...
- Summer training #2
A:不管有没有负数 一顿操作之后肯定只有正数 又因为A=A-B 所以最大值是一直在减小的 所以一定有结果 B:..一开始以为求min操作数 WA了2发 直接求所有数的GCD如果所有数的GCD都不是1的 ...
- 搭建单机版伪分布zookeeper集群
一.下载zookeeper http://mirrors.shu.edu.cn/apache/zookeeper/stable/ 我下载的是3.4.13版本 上传到liunx虚拟机上,解压 再复制出2 ...
- Python main()函数解析
__main__ — Top-level script environment '__main__'是顶级代码执行的作用域的名字. 当一个模块从标准input, 一个脚本文件,或一个交互命令read读 ...