一.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 无效:

  1. native method返回,JavaVM自动释放LocalRef;
  2. 用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引用类型的更多相关文章

  1. Android之NDK编程(JNI)

    转自:http://www.cnblogs.com/xw022/archive/2011/08/18/2144621.html NDK编程入门--C回调JAVA方法   一.主要流程 1.  新建一个 ...

  2. Delphi使用android的NDK是通过JNI接口,封装好了,不用自己写本地代码,直接调用

    一.Android平台编程方式:      1.基于Android SDK进行开发的第三方应用都必须使用Java语言(Android的SDK基于Java实现)      2.自从ndk r5发布以后, ...

  3. Android Studio NDK编程初探

    继上一篇学习了如何使用NDK编译FFMPEG后,接下来就是要学习如何在Android Studio中使用了. 经过参考和一系列的摸索,记录下具体步骤. 创建C++ Support的Android St ...

  4. Android JNI&NDK编程小结及建议

    前言 由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签 ...

  5. Android jni/ndk编程二:jni数据类型转换(primitive,String,array)

    一.数据类型映射概述 从我们开始jni编程起,就不可能避开函数的参数与返回值的问题.java语言的数据类型和c/c++有很多不同的地方,所以我们必须考虑当在java层调用c/c++函数时,怎么正确的把 ...

  6. Android jni/ndk编程五:jni异常处理

    在Java的编程中,我们经常会遇到各种的异常,也会处理各种的异常.处理异常在java中非常简单,我们通常会使用try-catch-finally来处理,也可以使用throw简单抛出一个异常.那么在jn ...

  7. Android之NDK环境配置+JNI开发+so文件编译

    前言 这边Android作为日常记录,虽然破坏了文章队形~   最近人工智能挺火的,也稍微了解了一些库,比如关于视觉库openCV.要在安卓下调用这些C/C++库,需要用到JNI开发,在此把过程分享一 ...

  8. Android Studio Ndk 编程

    如今开发Android程序基本都已经从Eclipse转到了Android Studio了, 近期项目需求, 须要用到ndk编程, 于是就折腾了一下. 开发环境 Android Studio 1.5.1 ...

  9. Android Studio JNI/NDK 编程简介(一)

    首先说一下概念及相关的东西: JNI : JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++).从Java1.1开始 ...

随机推荐

  1. C++虚函数和纯虚函数的用法和区别

    C++虚函数与纯虚函数用法与区别(转)   1. 虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能 ...

  2. SpringMVC----视图层框架

    Spring Web模型-视图-控制器(MVC)框架是围绕DispatcherServlet设计的,DispatcherServlet将接收的请求分派给应用程序.SpringMVC具有配置处理程序映射 ...

  3. inputrc命令

    问题:搭建ubuntu系统后,输入命令的第一个字符+上页按键,发现不能找到历史命令,找了好久才发现是因为/etc/inputrc没有对键盘映射的上页键和下页键进行设置. 解决方法: 修改文件/etc/ ...

  4. 解决xshell连接不上阿里云服务器问题

    最近购买了阿里云服务器准备玩玩,但是使用xshell连接阿里云服务器时,系统一直提示“Connection established. To escape to local shell, press ' ...

  5. 记一次root用户在本地登录及SSH连接均遭遇permission denied的问题排查经过

    某日一位老师反映,机房的6号节点无法登录了.一开始以为是为节点防火墙配置IP白名单时忘记了加进去,但随后发现此节点并未进行白名单配置,密码也一直未有变更,于是在自己的电脑上连接,发现终端里很快显示出了 ...

  6. GitHub的本地与远程

    首先要有一个github账户(这不是废话吗) 在linux中先安装git arch linux : pacman -S git 在终端里输入 ssh-keygen ##一直默认就可以了 将公钥加入到G ...

  7. Hive优化(十一)

    Hive优化 ​ Hive的存储层依托于HDFS,Hive的计算层依托于MapReduce,一般Hive的执行效率主要取决于SQL语句的执行效率,因此,Hive的优化的核心思想是MapReduce的优 ...

  8. 远程文件传输工具sftp、scp、rsync

    一.scp 格式 scp [options] [user@]host : /sourcefile /destpathscp [options] /sourcefile [user@]host:/des ...

  9. (九)zabbix监控web应用

    1)web应用监控介绍 使用zabbix自带的web场景可以监控url的状态码,响应时间,url的下载速度,非常的棒 思路:定义模板-->创建应用集--->定义web场景--->定义 ...

  10. hive中的 lateral view

    lateral view用于和split, explode等UDTF一起使用,它能够将一列数据拆成多行数据,在此基础上可以对拆分后的数据进行聚合. 一个简单的例子,假设我们有一张表pageAds,它有 ...