java如何做全局缓存_传智播客JNI第七讲 – JNI中的全局引用/局部引用/弱全局引用、缓存jfieldID和jmethodID的两种方式...
講解JNI中的全局引用/局部引用/弱全局引用、緩存jfieldID和jmethodID的兩種方式,并編寫兩種緩存方式的示例代碼。
1.從Java虛擬機(jī)創(chuàng)建的對象傳到本地C/C++代碼時(shí)會(huì)產(chǎn)生引用,根據(jù)Java的垃圾回收機(jī)制,只要有引用存在就不會(huì)出發(fā)該引用指向的Java對象的垃圾回收。
2.這些引用在JNI中分為三種:
全局引用:Global Reference
局部引用:Local Reference
若全局引用:Weak Global Reference since JDK1.2
3.局部引用
1)最常見的引用類型,基本上通過JNI返回來的引用都是局部引用。例如使用NewObject就會(huì)返回創(chuàng)建出來的實(shí)例的局部引用,局部引用只在該native函數(shù)中有效,所有在該函數(shù)中產(chǎn)生的局部引用,都會(huì)在函數(shù)返回的時(shí)候自動(dòng)釋放,也可以使用DeleteLocalRef函數(shù)手動(dòng)釋放該引用。
2)想一想既然局部引用能夠在函數(shù)返回時(shí)自動(dòng)釋放,為什么還需要DeleteLocalRef函數(shù)呢?
3)實(shí)際上,局部引用存在,就會(huì)防止其指向的對象被垃圾回收,尤其是當(dāng)一個(gè)局部引用指向一個(gè)很龐大的對象,或是在一個(gè)循環(huán)中生成了局部引用,最好的做法就是在使用完該對象后,或在循環(huán)尾部把這個(gè)引用釋放掉,以確保在垃圾回收器被處罰的時(shí)候被回收。
4)在局部引用的有效期中,可以傳遞到別的本地函數(shù)中,要強(qiáng)調(diào)的是他的有效期仍然只在一次的Java本地函數(shù)調(diào)用中,所以千萬不能用C++全局變量保存它或者把它定義為C++靜態(tài)局部變量。
4.全局引用
1)全局引用可以跨越當(dāng)前線程,在多個(gè)native函數(shù)中有效,不過需要編程人員手動(dòng)來釋放該引用,全局引用存在期間會(huì)防止在Java的垃圾回收。
2)與局部引用不同,全局引用的創(chuàng)建不是由JNI自動(dòng)創(chuàng)建的,全局引用時(shí)需要調(diào)用NewGlobalRef函數(shù),而釋放它需要使用ReleaseGlobalRef函數(shù)。
5.弱全局引用
1)Java1.2新出來的功能,與全局引用相似,創(chuàng)建跟刪除都需要由編程人員來進(jìn)行。這種引用與全局引用一樣可以再多個(gè)本地代碼有效,也跨越多線程有效,不一樣的是,這種引用將不會(huì)阻止垃圾回收器回收這個(gè)引用所指向的對象。
2)使用NewWeakGlobalRef跟ReleaseWeakGlobalRef來產(chǎn)生和解除引用。
6.關(guān)于引用的一些函數(shù)
jobject NewGlobalRef(jobject obj);
jobject NewLocalRef(jobject obj);
jobject NewWeakGlobalRef(jobject obj);
void DeleteGlobalRef(jobject obj);
void DeleteLocalRef(jobject obj);
void DeleteWeakGlobalRef(jobject obj);
jboolean IsSameObject(jobject obj1, jobject obj2); // 這個(gè)函數(shù)對于弱全局引用還有一個(gè)特別的功能,把NULL傳入要比較的對象中,就能夠判斷弱全局引用所指向的Java對象是否被回收。
7.緩存jfieldID,jmethodID
1)取得jieldID跟jmethodID的時(shí)候會(huì)通過該屬性、方法名稱加上簽名來查詢相應(yīng)的jfieldID,jmethodID。這種查詢相對來說開銷較大,我們可以將這些FieldID,MethodID緩存起來,這樣只需要查詢一次,以后就使用緩存起來的FieldID,MethodID。
2)介紹兩種緩存方式
1.在用的時(shí)候緩存
2.在Java類初始化時(shí)緩存
11)在第一次使用的時(shí)候緩存
在native code中使用static局部變量來保存已經(jīng)查詢過的id,這樣就不會(huì)再每次的函數(shù)調(diào)用時(shí)查詢,而只要第一次查詢成功后就保存起來了。
不過在這種情況下就不得不考慮多線程同時(shí)呼叫此函數(shù)時(shí)可能會(huì)招致同時(shí)查詢的危機(jī),不過這種情況是無害的,因?yàn)椴樵兺粋€(gè)屬性,方法的ID通常返回的是一樣的值。
JNIEXPORT void JNICALL Java_Test_native(JNIEnv* env, jobject obj){
static jfieldID fieldID_string = NULL;
jclass clazz = env->GEtObjectClass(obj);
if(fieldID_string == NULL){
fieldID_string = env->GetFieldID(clazz, "string", "Ljava/lang/String;");
}
// other code...
}
22)在Java類初始化的時(shí)候緩存
更好的一個(gè)方式就是在任何native函數(shù)調(diào)用前把id全部存起來。
我們可以讓Java在第一次加載這個(gè)類的時(shí)候首先調(diào)用本地代碼初始化所有的jfieldID,jmethodID,這樣的話,就可以省去多次的確定id是否存在的語句,當(dāng)然,這些jfieldID,jmethodID是定義在C/C++的全局。
使用這種方式的好處,當(dāng)Java類卸載或是重新加載的時(shí)候,也會(huì)重新呼叫該本地代碼來重新計(jì)算IDs。
課程最后總結(jié)
在這一課中,我們學(xué)習(xí)了:
1.最簡單的Java調(diào)用C/C++函數(shù)的方法
2.取得方法、屬性的ID,學(xué)會(huì)了取得/設(shè)置屬性,還有Java函數(shù)的調(diào)用。
3.Java/c++之間的字符串的轉(zhuǎn)換問題。
4.在C/C++下如何操作Java數(shù)組。
5.三種引用方式
6.如何緩存屬性和方法的ID
使用JNI的兩個(gè)弊端
1.使用了JNI,那么這個(gè)應(yīng)用就不能跨平臺(tái)了,如果需要移植到別的平臺(tái)上,那么native代碼就需要重新編寫。
2.Java是強(qiáng)類型的語言,而C/C++不是,你必須寫JNI時(shí)更小心。
3.盡量少使用本地代碼。
其它
1.異常處理
2.C/C++如何啟動(dòng)JVM
3.JNI跟多線程
介紹兩本書作為參考:
1)The Java Native Interface Programmer's Guide and Specification
2))JNI++ User Guide
總結(jié)
以上是生活随笔為你收集整理的java如何做全局缓存_传智播客JNI第七讲 – JNI中的全局引用/局部引用/弱全局引用、缓存jfieldID和jmethodID的两种方式...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为有朝一日自己弄个玩具玩而准备
- 下一篇: Qt安装教程-详细