【Android NDK 开发】JNI 引用 ( 局部引用 | 局部引用作用域 | 局部引用产生 | 局部引用释放 | 代码示例)
文章目錄
- I . JNI 引用數(shù)據(jù)類型
- II . JNI 引用 與 指針
- III . 局部引用 作用域
- IV . 局部引用 產(chǎn)生 與 釋放
- V . 局部引用 代碼示例
I . JNI 引用數(shù)據(jù)類型
1 . JNI 引用類型 : JNI 中 定義了 八種 Java 基本數(shù)據(jù)類型 , 其余的 jobject , jarray , jxxxArray , jclass , jstring 等都是引用類型 ;
① 規(guī)律 : 除 八種 基本數(shù)據(jù)類型之外的都是引用數(shù)據(jù)類型 ;
② 都是 Java 引用數(shù)據(jù)類型 : 這些數(shù)據(jù)類型都是 C/C++ 中定義的 Java 引用數(shù)據(jù)類型 , 其本質(zhì)是 C/C++ 環(huán)境中對(duì)應(yīng)的 Java 數(shù)據(jù)類型 ;
要注意將 JNI 中的 Java 類型引用 , 與 C/C++ 指針區(qū)分開 , 兩者概念不同 ;
2 . JNI 引用類型分為三類 :
① 局部引用 : 其只在作用域內(nèi)有效 , 內(nèi)存不可回收 ;
② 全局引用 : 全局有效 , 內(nèi)存不可回收 ;
③ 全局弱引用 : 全局有效 , 內(nèi)存不足時(shí)會(huì)被 JVM 回收 ;
內(nèi)存不可回收 , 如果內(nèi)存不足 , 會(huì)直接 OOM 內(nèi)存溢出 ;
II . JNI 引用 與 指針
在 JNI 中一定要將 引用 和 指針 區(qū)分開 ;
引用 是 Java 語言中的概念 , 指針 是 C/C++ 中的概念 ;
JNI 中 Java 引用類型 也是使用 C/C++ 指針表示的 , 這個(gè) 變量 就有了 兩重含義 , 即代表 Java 中的引用類型 , 又代表了 編程環(huán)境中的 指針 ;
這里注意 , 如果引用被 JVM 釋放了 , 即使指針還有值 , 也是不能用于 JNI 中與 Java 引用類型 相關(guān)的方法的 ;
本博客只討論引用相關(guān)的內(nèi)容 ;
III . 局部引用 作用域
1 . 局部引用作用域 :
局部引用只能在當(dāng)前作用域有效 ;
超出作用域
手動(dòng)釋放
上面 兩種情況 都會(huì)導(dǎo)致 局部引用變量 失效 ;
2 . 局部引用作用范圍 :
① 空間 : 不能 跨線程 , 跨方法調(diào)用 , 僅在本作用域有效 ;
② 時(shí)間 : 創(chuàng)建后可以使用 , 手動(dòng)釋放 或 作用域結(jié)束 引用被釋放不可使用 ;
IV . 局部引用 產(chǎn)生 與 釋放
1 . 局部引用產(chǎn)生 與 釋放 :
① 局部引用產(chǎn)生 : 使用 NewXXX / FindXXX 等 大多數(shù) JNI 方法 默認(rèn)創(chuàng)建的 Java 引用類型對(duì)象 都是局部引用 ;
② 局部引用釋放 : 調(diào)用 DeleteLocalRef 方法 釋放該局部引用 ;
2 . 局部引用的兩種釋放方式 :
① 自動(dòng)釋放 : 在方法作用域結(jié)束后 , JVM 自動(dòng)釋放上述 局部引用 變量 ;
② 手動(dòng)釋放 : 通過調(diào)用 DeleteLocalRef 方法手動(dòng)釋放 ;
3 . 局部引用推薦釋放方式 :
① 內(nèi)存角度考慮 : 局部引用 釋放盡量靈活 , 不要等待自動(dòng)釋放 , 在使用完畢后 建議就手動(dòng)釋放 , 盡早回收內(nèi)存 ;
② 自動(dòng)釋放情況 :如果該 引用 一直到最后都要使用 , 那么可以不進(jìn)行手動(dòng)釋放 ;
③ 建議用法 : 局部引用建議都要手動(dòng)釋放 , 哪怕是在作用域最后 , 也要進(jìn)行手動(dòng)釋放
V . 局部引用 代碼示例
局部引用代碼示例 :
extern "C" JNIEXPORT void JNICALL Java_kim_hsl_jni_MainActivity_jniLocalReferenceTest(JNIEnv *env, jobject instance) {/*局部引用局部引用只能在當(dāng)前作用域有效超出作用域手動(dòng)釋放上面 兩種情況 都會(huì)導(dǎo)致 該局部變量都會(huì)失效局部引用作用范圍 :空間 : 不能 跨線程 , 跨方法調(diào)用 , 僅在本作用域有效時(shí)間 : 創(chuàng)建后可以使用 , 手動(dòng)釋放 或 作用域結(jié)束 引用被釋放不可使用局部引用 創(chuàng)建 : 使用 NewXXX / FindXXX 等 大多數(shù) JNI 方法 默認(rèn)創(chuàng)建的都是局部引用釋放 : 調(diào)用 DeleteLocalRef 方法 釋放該局部引用關(guān)于上面的三個(gè)創(chuàng)建的 局部引用 有兩種釋放方式方式一 : 在方法作用域結(jié)束后 , VM 自動(dòng)釋放上述變量方式二 : 通過調(diào)用 DeleteLocalRef 方法手動(dòng)釋放建議使用方式二 :局部引用 釋放盡量靈活 , 不要等待自動(dòng)釋放 , 在使用完畢后 建議就手動(dòng)釋放 , 今早回收內(nèi)存如果該 引用 一直到最后都要使用 , 那么可以不進(jìn)行手動(dòng)釋放 ;建議用法 : 局部引用建議都要手動(dòng)釋放 , 哪怕是在作用域最后 , 也要進(jìn)行手動(dòng)釋放局部引用傳遞到 Java 層 , 該傳遞是拷貝傳遞 , JNI 中該釋放還是釋放 , 不影響 Java 層使用引用概念 :這里要將 引用 和 指針的概區(qū)分清楚 ;class_teacher 引用在 作用域結(jié)束時(shí) 會(huì)被釋放 , 不能將其用于 JNI 反射 Java 類的方法和字段其指針值不為空 , 仍然有值 , 其仍然指向一個(gè)地址 , 但是地址中的數(shù)據(jù)被釋放了*/// 1 . 獲取 Teacher 類 ( 該變量需要釋放 )jclass class_teacher = env->FindClass("kim/hsl/jni/Teacher");// 2 . 查找構(gòu)造方法jmethodID method_init = env->GetMethodID(class_teacher, "<init>", "(ILjava/lang/String;)V");// 3 . 準(zhǔn)備 Java 類型參數(shù) ( 該變量需要釋放 )// 此處特別注意 : 傳入到 Java 方法中的參數(shù)都必須是 Java 參數(shù)jint teacher_age = 88;jstring teacher_name = env->NewStringUTF("Tom Wang");// 4 . 創(chuàng)建 Teacher 對(duì)象 ( 該變量需要釋放 )jobject teacher = env->NewObject(class_teacher, method_init, teacher_age, teacher_name);// 5 . 釋放上面通過 FindClass NewStringUTF NewObject 創(chuàng)建的引用變量 , 否則會(huì)造成內(nèi)存泄漏// 使用完這三個(gè)引用之后 , 不再使用 ; 這里特別建議手動(dòng)釋放三個(gè)引用// 如果不手動(dòng)釋放 , 在 該引用 作用域 結(jié)束后 , 也會(huì)自動(dòng)釋放掉env->DeleteLocalRef(teacher_name);env->DeleteLocalRef(teacher);env->DeleteLocalRef(class_teacher);}總結(jié)
以上是生活随笔為你收集整理的【Android NDK 开发】JNI 引用 ( 局部引用 | 局部引用作用域 | 局部引用产生 | 局部引用释放 | 代码示例)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android NDK 开发】JNI
- 下一篇: 【Android NDK 开发】JNI