【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);}總結
以上是生活随笔為你收集整理的【Android NDK 开发】JNI 引用 ( 局部引用 | 局部引用作用域 | 局部引用产生 | 局部引用释放 | 代码示例)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android NDK 开发】JNI
- 下一篇: 【Android NDK 开发】JNI