前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Android NDK 开发】JNI 引用 ( 局部引用 | 局部引用作用域 | 局部引用产生 | 局部引用释放 | 代码示例)

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

作者头像
韩曙亮
发布2023-03-27 17:54:17
6070
发布2023-03-27 17:54:17
举报
文章被收录于专栏:韩曙亮的移动开发专栏

文章目录

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 . 局部引用 代码示例

局部引用代码示例 :

代码语言:javascript
复制
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);

}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-02-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
    • I . JNI 引用数据类型
      • II . JNI 引用 与 指针
        • III . 局部引用 作用域
          • IV . 局部引用 产生 与 释放
            • V . 局部引用 代码示例
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档