局部引用:

JNI 函数内部创建的 jobject对象及其子类( jclass、 jstring、 jarray等) 对象都是局部引用,它们在 JNI 函数返回后无效;

一般情况下,我们应该依赖 JVM 去自动释放 JNI 局部引用;但下面两种情况必须手动调用 DeleteLocalRef()去释放:

(在循环体或回调函数中)创建大量 JNI 局部引用,即使它们并不会被同时使用,因为 JVM 需要足够的空间去跟踪所有的 JNI 引用,所以可能会造成内存溢出或者栈溢出;

如果对一个大的 Java 对象创建了 JNI 局部引用,也必须在使用完后手动释放该引用,否则 GC 迟迟无法回收该 Java 对象也会引发内存泄漏.

全局引用:

全局引用允许你持有一个 JNI 对象更长的时间,直到你手动销毁;但需要显式调用 NewGlobalRef()和 DeleteGlobalRef():

class MyPeer {

private:

jstring s;

public:

MyPeer(JNIEnv* env, jstring s) {

this->s = env->NewGlobalRef(s);

}

~MyPeer() {

env->DeleteGlobalRef(s);

s = NULL;

}

};

弱全局引用

弱全局引用类似 Java 中的弱引用,它允许对应的 Java 对象被 GC 回收;

类似地,创建和释放也是通过 NewWeakGlobalRef()和 DeleteWeakGlobalRef();

调用 IsSameObject(env, jobj, NULL)可以判断该弱全局引用指向的 Java 对象是否已被 GC 回收。

jobject 对象的引用值不唯一

同一个 jobject对象的不同引用可能拥有不同的值,比如同一 jobject对象每次调用 NewGlobalRef()可能返回不同的值;

要检查两个引用是否指向同一个 jobject对象,必须调用 IsSameObject(),而不要使用 ==去比较;

用于描述一个 jobject对象的 32 位值可能在方法多次调用后发生变化,而两个不同 jobject对象却可能在多次方法调用拥有相同的值,所以千万不能将 jobject对象的值当作 key 使用;

jmethodID 和 jfieldID:

在 JNI 层执行 Java 代码常用到 FindClass()、 GetMethodID()、 GetFieldID();

但只有第一个函数返回的 jclass属于 JNI (局部)引用对象,而 jmethodID和 jfieldID并不是,它们是指向内部 Runtime 数据结构的指针;

实际上这些 ID 是用于缓存的静态对象:第一次查找会做一次字符串比较,但后面再次调用就能直接读取而变得很快;

JVM 会保证这些 ID 是合法的,直到 Class被 unload;

所以, jmethodID和 jfieldID是不需要手动释放的,当然也不能作为 JNI 全局引用。

其他非 JNI 引用:

除了上面提到的 ID,类似 GetStringUTFChars()和 GetByteArrayElements()/ GetCharArrayElements()等函数返回的也是 Raw Data 指针,而非 JNI 引用;

在调用相对应的 ReleaseXXX()函数释放前,它们都是合法的;

批量操作 JNI 引用:

一般情况下要避免大量创建 JNI 局部引用,最好用完后立即释放(实际上目前的实现只预留了 16 个局部引用的空间);

如果确实需要大量操作 JNI 局部引用,要么调用 EnsureLocalCapacity()指定更多的空间,要么调用 PushLocalFrame()/ PopLocalFrame()批量分配/释放:

env->PushLocalFrame(128);

jobjectArray array = env->NewObjectArray(128, gMyClass, NULL);

for (int i = 0; i < 128; ++i) {

env->SetObjectArrayElement(array, i, newMyClass(i));

}

env->PopLocalFrame(array);

开启 CheckJNI 检查 JNI 引用问题:

Android 提供了一种叫做 CheckJNI 的模式用于检测常见的 JNI 错误,其中和 JNI 引用相关的错误有:

将 DeleteGlobalRef()/ DeleteLocalRef()用于错误的 JNI 引用类型;

jfieldID/ jmethodID为空或者类型不合法;

但是 CheckJNI 暂时还不能检测 JNI 局部引用的滥用问题,比如:存储了一个 JNI 局部引用,然后在 JNI 函数返回后继续使用。这种情况很显然应该使用 NewGlobalRef()创建全局 JNI 引用。

开启 CheckJNI 只需一行命令即可:

adb shell setprop debug.checkjni 1

参考:

android jni deletelocalref,JNI 引用, DeleteLocalRef使用场景详解相关推荐

  1. [免费专栏] Android安全之数据存储与数据安全「详解」

    也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 Android安全付费专栏长期更新,本篇最新内容请前往: [ ...

  2. Android系统性能优化(60)---LeakCanary使用详解

    Android内存优化(六)LeakCanary使用详解 1.概述 如果使用MAT来分析内存问题,会有一些难度,并且效率也不是很高,对于一个内存泄漏问题,可能要进行多次排查和对比.  为了能够简单迅速 ...

  3. 【C++】引用以及关联函数(详解)

    文章目录 [C++]引用以及关联函数(详解) 1.引用 1.1引用概念 1.2引用的使用 1.3引用的特性 1.4常引用 1.4.1取别名的权限问题: const常量: double和int相互引用: ...

  4. 转:修改ETM,用Ogre实现《天龙八部》地形与部分场景详解

    本文主要讲的是<天龙八部>游戏的地形和一部分场景的具体实现,使用C++, Ogre1.6,我摸索了段时间,可能方法用的并不是最好的,但好歹实现了.文章可能讲得有点罗嗦,很多简单的东西都讲了 ...

  5. Android四大组件之bindService源码实现详解

        Android四大组件之bindService源码实现详解 Android四大组件源码实现详解系列博客目录: Android应用进程创建流程大揭秘 Android四大组件之bindServic ...

  6. python脚本例子_python dict 字典 以及 赋值 引用的一些实例(详解)

    最近在做一个很大的数据库方面的东东,要用到根据数值来查找,于是想到了python中的字典,平时没用过dict这个东东 用的最多的还是 list 和 tuple (网上查 用法一大堆) 看了一下创建字典 ...

  7. android listview ontouchlistener,Android ListView监听滑动事件的方法(详解)

    ListView的主要有两种滑动事件监听方法,OnTouchListener和OnScrollListener 1.OnTouchListener OnTouchListener方法来自View中的监 ...

  8. java8 方法引用详解_Java8中如何通过方法引用获取属性名详解

    前言 在我们开发过程中常常有一个需求,就是要知道实体类中Getter方法对应的属性名称(Field Name),例如实体类属性到数据库字段的映射,我们常常是硬编码指定 属性名,这种硬编码有两个缺点. ...

  9. Android 事件分发机制分析及源码详解

    Android 事件分发机制分析及源码详解 文章目录 Android 事件分发机制分析及源码详解 事件的定义 事件分发序列模型 分发序列 分发模型 事件分发对象及相关方法 源码分析 事件分发总结 一般 ...

  10. android edittext 过滤英文名称,Android 限制edittext 整数和小数位数 过滤器(详解)

    写了一个过滤器,根据需要限制edittext输入的整数和小数位,如下代码: package allone.verbank.apad.client.component; import android.t ...

最新文章

  1. 4岁学编程,19岁创办以太坊,4年十亿身家!
  2. JQuery学习笔记02-选择器把需要的东西揪出来(基础)
  3. mysql 导入文件提示 --secure-file-priv option 问题
  4. the graphics window has detected an error and is not able to ini
  5. Python-GUI编程PyQT5案例:注册界面扇形菜单动画及相关事件处理
  6. Docker技术快速精通指南
  7. 思科虚拟机配置dhpc服务器,思科模拟器配置DHCP
  8. 如何获取系统的临时目录路径?
  9. 开源、高质量QR码多语言生成库
  10. Bootstrap 两端对齐的导航
  11. 删除归档_备份与归档的“罗生门”
  12. 服务器远程登陆最大连接数,解决登录Windows服务器时超出了最大允许连接数
  13. BZOJ1588: [HNOI2002]营业额统计
  14. 设计模式-----桥接模式(Bridge Pattern)(转)
  15. mysql内连接和左连接的区别_MySQL连接查询 内连接和外连接的区别
  16. hfs网络文件服务器如何设置,hfs网络文件服务器的教程
  17. linux运行脚本运行不了,shell脚本在windows上可以执行,Linux上面不能执行
  18. HTML+CSS+JS网站设计——上海美食(8页) 酒水网页设计作业,甜品美食网页制作作业, 学生零食网页作业
  19. Android中Intent的介绍
  20. 计算机硬盘隐,终极电脑磁盘隐藏方法大全

热门文章

  1. 三年MacBook Pro使用经验分享必备的20款mac良心软件
  2. 在线cad版本转换_智慧小区弱电工程设计图纸(CAD版本)
  3. CSS炫丽的字体,含中文字体,在线字体
  4. 使用阿里云工具迁移本地仓库至私服
  5. Ebay Trading API整理
  6. vue-cli使用pdf.js插件浏览pdf文件,禁止下载打印复制粘贴。
  7. 安卓开发打造闪光控件效果
  8. qbs java_Qt构建工具QBS之零 —— QBS 概览
  9. 虚拟网络编辑器三种模式工作原理详细介绍(桥接-网络地址转换-主机模式)
  10. 千万不要在电脑中安装净网大师软件阿