Android NDK 开发(四)JNI 中局部引用、全局引用和弱全局引用

news/2024/7/20 12:47:46 标签: 移动开发, python, 内存管理

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

前言

做过Java的朋友都知道,内存管理这一块是完全透明的,new一个类的实例时,只知道创建完这个类的实例后,会返回这个实例的一个引用,然后拿着这个引用去访问它的成员了(属性、方法),完全不用管JVM内部怎么实现的,如何为新建的对象申请内存,使用完之后如何释放内存,只需要知道有个垃圾回收器在处理这些事情就行了,然而,从Java虚拟机创建的对象传到C/C++代码时会产生引用,根据Java的垃圾回收机制,只要有引用存在就不回触发该引用所指向Java对象的垃圾回收;这些引用在JNI 中分为3种:全局引用(Global Reference)、局部引用 (Local Reference)、弱全局引用 (Week Global Reference) since JDK1.2。


原文链接请标明:
http://blog.csdn.net/u011974987/article/details/52848908
本文出自:【stromxu的博客】

正文

三种引用的区别

1、全局引用

全局引用可以跨方法、跨线程使用,直到被开发者显式释放。类似局部引用,一个全局引用在被释放前保证引用对象不被GC回收。和局部引用不同的是,没有那么多函数能够创建全局引用。能创建全局引用的函数只有 NewGlobalRef。以下例子说明了如何使用一个全局引用。

java native方法:

    public native void createGlobalRef();

    public native String getGlobalRef();

    public native void deleteGlobalRef();

jni实现:

//全局引用
//共享(可以跨多个线程),手动控制内存使用
jstring global_str;

//创建
JNIEXPORT void JNICALL Java_com_study_jni_JniTest_createGlobalRef(JNIEnv *env, jobject jobj){
    jstring obj = (*env)->NewStringUTF(env, "jni development is powerful!");
    global_str = (*env)->NewGlobalRef(env, obj);
}

//获得
JNIEXPORT jstring JNICALL Java_com_study_jni_JniTest_getGlobalRef(JNIEnv *env, jobject jobj){
    return global_str;
}

//释放
JNIEXPORT void JNICALL Java_com_study_jni_JniTest_deleteGlobalRef(JNIEnv *env, jobject jobj){
    (*env)->DeleteGlobalRef(env, global_str);
}

2、局部引用

一个局部引用仅在创建它的native函数及该函数调用的函数中有效。在一个native函数执行期间创建的所有局部引用将在该函数返回时被释放,创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性。

//模拟:循环创建数组
JNIEXPORT void JNICALL Java_com_study_jni_JniTest_localRef(JNIEnv *env, jobject jobj){
    int i = 0;
    for (; i < 5; i++){
        //创建Date对象
        jclass cls = (*env)->FindClass(env, "java/util/Date");
        jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "<init>", "()V");
        jobject obj = (*env)->NewObject(env, cls, constructor_mid);
        //此处省略一百行代码...

        //不在使用jobject对象了
        //通知垃圾回收器回收这些对象
        //释放局部引用
        (*env)->DeleteLocalRef(env, obj);
        //此处省略一百行代码...
    }
}

上面代码中,省略了和我们无关紧要的代码,通过FindClass返回一个对java.util.Date对象的局部引用。


3、弱全局引用

节省内存,在内存不足时可以是释放所引用的对象,可以引用一个不常用的对象,如果为NULL,临时创建,弱全局引用使用NewGlobalWeakRef创建,使用DeleteGlobalWeakRef释放。下面简称弱引用。与全局引用类似,弱引用可以跨方法、线程使用。但与全局引用很重要不同的一点是,弱引用不会阻止GC回收它引用的对象,所以在使用时需要多加小心,它所引用的对象可能是不存在的或者已经被回收。

1.创建弱全局引用

用NewWeakGlobalRef函数对弱全局引用进行初始化,例如:

jclass weakGlobalcls
weakGlobalcls = (*env)->NewWeakGlobalRef(env,localclazz);
2.引用的比较

给定两个引用(不管是全局、局部还是弱全局引用),我们只需要调用IsSameObject来判断它们两个是否指向相同的对象。例如:(*env)->IsSameObject(env, obj1, obj2)
如果obj1和obj2指向相同的对象,则返回JNI_TRUE(或者1),否则返回JNI_FALSE(或者0)。有一个特殊的引用需要注意:NULL,JNI中的NULL引用指向JVM中的null对象。如果obj是一个局部或全局引用,使用(*env)->IsSameObject(env, obj, NULL) 或者 obj == NULL 来判断obj是否指向一个null对象即可。但需要注意的是,IsSameObject用于弱全局引用与NULL比较时,返回值的意义是不同于局部引用和全局引用的。比如:

if(JNI_FALSE == (*env)->IsSameObject(env,weakGlobalcls,NULL)){
//TODO 对象未被回收,可以使用
}else{
//TODO 对象被垃圾回收器回收,不能使用
}

以上就是学习这jni 的三种引用的简单使用,相关的知识并没有深入详细的说明!O(∩_∩)O~~

转载于:https://my.oschina.net/xuhaozi/blog/780411


http://www.niftyadmin.cn/n/976867.html

相关文章

from scipy.misc import imread 报错解决方法

试过很多方法不行的话&#xff0c;建议使用这个命令试试:\color {red} {建议使用这个命令试试:}建议使用这个命令试试: pip install pillow

采用shc工具加密Shell脚本

采用shc工具加密Shell脚本&#xff0c;以提高shell脚本文件的安全性。介绍&#xff1a;当我们写的shell脚本&#xff0c;存在有敏感信息如账号密码&#xff0c;于是想加强脚本的安全性&#xff1b;还有不想让别人查看/修改您的shell核心代码等等情况。都可使用以下工具进行加密…

26.Azure备份服务器(下)

如果您喜欢我的文章&#xff0c;请在右上角处点击《关注》支持一下&#xff0c;谢谢&#xff01;最后有人好奇说目前只挂在了1个SAS盘和1个SATA盘&#xff0c;容量那么小&#xff0c;随着业务的增大&#xff0c;我需要备份的空间也随着增大&#xff0c;那么我该怎么加大容量呢&…

豆瓣爬虫btmd_12_Mamba文件

链接: https://pan.baidu.com/s/1fxgu8B9LHV839-XgNB0M-g 提取码&#xff1a;rb2k

前端解决跨域问题的8种方案

为什么80%的码农都做不了架构师&#xff1f;>>> 本文和大家分享的主要是前端开发中&#xff0c;跨域问题的几种解决办法&#xff0c;希望对大家有帮助。 1.同源策略如下&#xff1a; URL说明是否允许通信 特别注意两点&#xff1a; 第一&#xff0c; 如果是协议和端…

Spring Data(一)概念和仓库的定义

Spring Data&#xff08;一&#xff09;概念和仓库的定义 Spring Data的主要任务是为数据访问提供一个相似的、一致的、基于Spring的编程模型&#xff0c;同时又保留着下面各个数据存储的特征。它使得使用数据访问技术非常的简单&#xff0c;包括关系型和非关系型数据库、map-r…

nodemon : 无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\nodemon.ps1因为在此系统上禁止运行脚本。

1、找到Windows PowerShell&#xff0c;右键&#xff0c;以管理员身份进行&#xff1a; 2、输入命令&#xff1a; set-ExecutionPolicy RemoteSigned 选择Y 3、查看是否修改成功&#xff1a; get-ExecutionPolicy修改成功即可运行nodemon命令。

Java (基础自总结)

为什么80%的码农都做不了架构师&#xff1f;>>> Java 基础 一、命名规则和规范&#xff1a;&#xff08;规则必须严格遵守&#xff1b;规范是约定是良好的习惯&#xff09; a) 变量命名&#xff1a; 注*数字&#xff0c;字母&#xff0c;下划线,$符号组成 开头不能…