【Android NDK 开发】JNI 引用 ( 局部引用 | 局部引用作用域 | 局部引用产生 | 局部引用释放 | 代码示例)

简介: 【Android NDK 开发】JNI 引用 ( 局部引用 | 局部引用作用域 | 局部引用产生 | 局部引用释放 | 代码示例)

文章目录

I . JNI 引用数据类型

II . JNI 引用 与 指针

III . 局部引用 作用域

IV . 局部引用 产生 与 释放

V . 局部引用 代码示例



I . JNI 引用数据类型


1 . JNI 引用类型 : JNI 中 定义了 八种 Java 基本数据类型 , 其余的 jobject , jarray , jxxxArray , jclass , jstring 等都是引用类型 ;



① 规律 : 除 八种 基本数据类型之外的都是引用数据类型 ;


② 都是 Java 引用数据类型 : 这些数据类型都是 C/C++ 中定义的 Java 引用数据类型 , 其本质是 C/C++ 环境中对应的 Java 数据类型 ;



要注意将 JNI 中的 Java 类型引用 , 与 C/C++ 指针区分开 , 两者概念不同 ;



2 . JNI 引用类型分为三类 :



① 局部引用 : 其只在作用域内有效 , 内存不可回收 ;


② 全局引用 : 全局有效 , 内存不可回收 ;


③ 全局弱引用 : 全局有效 , 内存不足时会被 JVM 回收 ;



内存不可回收 , 如果内存不足 , 会直接 OOM 内存溢出 ;




II . JNI 引用 与 指针


在 JNI 中一定要将 引用 和 指针 区分开 ;


引用 是 Java 语言中的概念 , 指针 是 C/C++ 中的概念 ;


JNI 中 Java 引用类型 也是使用 C/C++ 指针表示的 , 这个 变量 就有了 两重含义 , 即代表 Java 中的引用类型 , 又代表了 编程环境中的 指针 ;


这里注意 , 如果引用被 JVM 释放了 , 即使指针还有值 , 也是不能用于 JNI 中与 Java 引用类型 相关的方法的 ;



本博客只讨论引用相关的内容 ;




III . 局部引用 作用域


1 . 局部引用作用域 :



局部引用只能在当前作用域有效 ;


超出作用域

手动释放

上面 两种情况 都会导致 局部引用变量 失效 ;



2 . 局部引用作用范围 :


① 空间 : 不能 跨线程 , 跨方法调用 , 仅在本作用域有效 ;


② 时间 : 创建后可以使用 , 手动释放 或 作用域结束 引用被释放不可使用 ;




IV . 局部引用 产生 与 释放


1 . 局部引用产生 与 释放 :


① 局部引用产生 : 使用 NewXXX / FindXXX 等 大多数 JNI 方法 默认创建的 Java 引用类型对象 都是局部引用 ;


② 局部引用释放 : 调用 DeleteLocalRef 方法 释放该局部引用 ;



2 . 局部引用的两种释放方式 :



① 自动释放 : 在方法作用域结束后 , JVM 自动释放上述 局部引用 变量 ;


② 手动释放 : 通过调用 DeleteLocalRef 方法手动释放 ;



3 . 局部引用推荐释放方式 :



① 内存角度考虑 : 局部引用 释放尽量灵活 , 不要等待自动释放 , 在使用完毕后 建议就手动释放 , 尽早回收内存 ;


② 自动释放情况 :如果该 引用 一直到最后都要使用 , 那么可以不进行手动释放 ;


③ 建议用法 : 局部引用建议都要手动释放 , 哪怕是在作用域最后 , 也要进行手动释放




V . 局部引用 代码示例


局部引用代码示例 :


extern "C"
JNIEXPORT void JNICALL
Java_kim_hsl_jni_MainActivity_jniLocalReferenceTest(JNIEnv *env, jobject instance) {
    /*
        局部引用
            局部引用只能在当前作用域有效
                超出作用域
                手动释放
            上面 两种情况 都会导致 该局部变量都会失效
        局部引用作用范围 :
                空间 : 不能 跨线程 , 跨方法调用 , 仅在本作用域有效
                时间 : 创建后可以使用 , 手动释放 或 作用域结束 引用被释放不可使用
        局部引用 创建 : 使用 NewXXX / FindXXX 等 大多数 JNI 方法 默认创建的都是局部引用
                释放 : 调用 DeleteLocalRef 方法 释放该局部引用
        关于上面的三个创建的 局部引用 有两种释放方式
            方式一 : 在方法作用域结束后 , VM 自动释放上述变量
            方式二 : 通过调用 DeleteLocalRef 方法手动释放
        建议使用方式二 :
            局部引用 释放尽量灵活 , 不要等待自动释放 , 在使用完毕后 建议就手动释放 , 今早回收内存
            如果该 引用 一直到最后都要使用 , 那么可以不进行手动释放 ;
            建议用法 : 局部引用建议都要手动释放 , 哪怕是在作用域最后 , 也要进行手动释放
        局部引用传递到 Java 层 , 该传递是拷贝传递 , JNI 中该释放还是释放 , 不影响 Java 层使用
        引用概念 :
            这里要将 引用 和 指针的概区分清楚 ;
            class_teacher 引用在 作用域结束时 会被释放 , 不能将其用于 JNI 反射 Java 类的方法和字段
                          其指针值不为空 , 仍然有值 , 其仍然指向一个地址 , 但是地址中的数据被释放了
     */
    // 1 . 获取 Teacher 类 ( 该变量需要释放 )
    jclass class_teacher = env->FindClass("kim/hsl/jni/Teacher");
    // 2 .  查找构造方法
    jmethodID method_init = env->GetMethodID(class_teacher, "<init>", "(ILjava/lang/String;)V");
    // 3 . 准备 Java 类型参数 ( 该变量需要释放 )
    //     此处特别注意 : 传入到 Java 方法中的参数都必须是 Java 参数
    jint teacher_age = 88;
    jstring teacher_name = env->NewStringUTF("Tom Wang");
    // 4 .  创建 Teacher 对象 ( 该变量需要释放 )
    jobject teacher = env->NewObject(class_teacher, method_init, teacher_age, teacher_name);
    // 5 .  释放上面通过 FindClass NewStringUTF NewObject 创建的引用变量 , 否则会造成内存泄漏
    //     使用完这三个引用之后 , 不再使用 ; 这里特别建议手动释放三个引用
    //     如果不手动释放 , 在 该引用 作用域 结束后 , 也会自动释放掉
    env->DeleteLocalRef(teacher_name);
    env->DeleteLocalRef(teacher);
    env->DeleteLocalRef(class_teacher);
}



目录
相关文章
|
7月前
|
编解码 Java Android开发
安卓虚拟摄像头免root版,虚拟摄像头替换真实摄像头,jar代码开源分享
通过动态替换摄像头输入流的方式实现虚拟摄像头功能,代码经过简化展示核心逻辑。实际开发中还需要考虑视频编解码优化
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
1241 1
|
存储 前端开发 测试技术
Android kotlin MVVM 架构简单示例入门
Android kotlin MVVM 架构简单示例入门
364 1
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
Android远程连接和登录FTPS服务代码(commons.net库)
376 1
|
Android开发 Swift iOS开发
探索安卓与iOS开发的差异:从代码到用户体验
【10月更文挑战第5天】在移动应用开发的广阔天地中,安卓和iOS两大平台各占半壁江山。它们在技术架构、开发环境及用户体验上有着根本的不同。本文通过比较这两种平台的开发过程,揭示背后的设计理念和技术选择如何影响最终产品。我们将深入探讨各自平台的代码示例,理解开发者面临的挑战,以及这些差异如何塑造用户的日常体验。
|
存储 Java Android开发
🔥Android开发大神揭秘:从菜鸟到高手,你的代码为何总是慢人一步?💻
在Android开发中,每位开发者都渴望应用响应迅速、体验流畅。然而,代码执行缓慢却是常见问题。本文将跟随一位大神的脚步,剖析三大典型案例:主线程阻塞导致卡顿、内存泄漏引发性能下降及不合理布局引起的渲染问题,并提供优化方案。通过学习这些技巧,你将能够显著提升应用性能,从新手蜕变为高手。
252 2
|
Java Android开发 C++
🚀Android NDK开发实战!Java与C++混合编程,打造极致性能体验!📊
在Android应用开发中,追求卓越性能是不变的主题。本文介绍如何利用Android NDK(Native Development Kit)结合Java与C++进行混合编程,提升应用性能。从环境搭建到JNI接口设计,再到实战示例,全面展示NDK的优势与应用技巧,助你打造高性能应用。通过具体案例,如计算斐波那契数列,详细讲解Java与C++的协作流程,帮助开发者掌握NDK开发精髓,实现高效计算与硬件交互。
598 1
|
JSON JavaScript 前端开发
Android调用Vue中的JavaScript代码
Android调用Vue中的JavaScript代码
406 3
|
安全 Java 网络安全
Android远程连接和登录FTPS服务代码(commons.net库)
很多文章都介绍了FTPClient如何连接ftp服务器,但却很少有人说如何连接一台开了SSL认证的ftp服务器,现在代码来了。
456 2
|
存储 Java Android开发
🔥Android开发大神揭秘:从菜鸟到高手,你的代码为何总是慢人一步?💻
【7月更文挑战第28天】在Android开发中,每位开发者都追求极致的用户体验。然而,“代码执行慢”的问题时常困扰着开发者。通过案例分析,我们可探索从新手到高手的成长路径。
180 3

热门文章

最新文章