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