一.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. RAD Studio 10.3.2七大新功能介绍

    RAD Studio 10.3.2七大新功能 Delphi支持macOS 64位应用的开发. C++Builder中Windows 64位平台支持C ++ 17特性. C ++ LSP 代码洞察改进. ...

  2. sql 批量触发器

    SET QUOTED_IDENTIFIER ON SET ANSI_NULLS ON GO ALTER TRIGGER [dbo].[tr_insert_update_delete_sscode] O ...

  3. ISO/IEC 15444-12 MP4 封装格式标准摘录 4

    目录 Movie Fragments Movie Extends Box Movie Extends Header Box Track Extends Box Movie Fragment Box M ...

  4. DA_06_高级文本处理命令

    Linux中没有盘符这个概念,只有一个根目录“/”,所有文件都在它下面:点击计算机,下面存放的都是根目录下的东西: 2.6 文本文件编辑命令 1.cat 命令用于查看纯文本文件(内容较少的:一次性全部 ...

  5. 清北学堂dp图论营游记day5

    ysq主讲: tarjan缩点+拓扑+dij最短路. floyd..... 单源..最长路... 建正反两个图. 二分答案,把大于答案的边加入到新图中,如果能走过去到终点,就可以. 或者:从大到小加边 ...

  6. asp.net操纵Oracle存储过程

    在bloginfo数据库中,利用用户名 system 密码 scy251147 选择超级管理员登陆  创建如下存储过程:  1 /*存储过程*/ 2 create or replace procedu ...

  7. Java中的equals,==,compareTo和compare的比较

    Java中的equals(),==,compareTo()和compare() 首先只有==可以用作两个基本类型数据之间的比较,当然是值比较.当用作两个对象比较时,比较的是对象引用,而不是值比较. 其 ...

  8. 多组件共享-vuex —— 使用vuex 报错 actions should be function or object with ”handler“

    vuex分模块使用时出现的问题,单文件暂时没有用到 原因是在action 文件中没有任何定义(即:文件为空)或则 action 没有任何方法返回,将action在模块引用时去掉即可 转自:https: ...

  9. robotframework 模拟滚动鼠标到底部

    Execute Javascript var ele = document.getElementsByClassName("right_main")[0];ele.scrollTo ...

  10. 题解 [ZJOI2008]树的统计Count

    [ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u ...