天天看點

JNI局部引用,全局引用,弱全局引用(Weak Global Reference)介紹

作者:編編成程
JNI局部引用,全局引用,弱全局引用(Weak Global Reference)介紹

局部引用:

通過NewLocalRef以及各種JNI接口建立(FindClass, NewObject, GetObjectClass, NewCharArray)等傳回的對象。他會阻止GC對對象的回收,他不支援在本地函數中跨函數使用,不能跨線程使用。函數傳回後局部引用所引用的對象會被JVM自動釋放,或者你也可以通過調用(*env)->DeleteLocalRef(env, local_ref)進行顯示釋放.當方法傳回到Java層之後,局部引用會被JVM自動釋放,你可能會為了提高程式性能,在C++端做static的緩存,但這是錯誤的,因為JVM仍然會釋放掉他,你存了一個野指針。比如我們cls_string = (*env)->FindClass(env, "java/lang/String"), FindClass會在局部引用表上建立一個局部引用,并傳回這個局部引用的位址,這個局部引用指向Java Heap上的String Class對象。

JNI局部引用,全局引用,弱全局引用(Weak Global Reference)介紹

要避免這個現象,你隻需要把你這個局部引用改成全局引用就可以了

cls_string = (jclass) (*env)->NewGlobalRef(env,(*env)->FindClass(env,"java/lang/String"));

全局引用:

調用NewGlobalRef(),參數為局部引用,進行二次建立。阻止GC對其回收,可以跨方法,跨線程使用,JVM不會指定釋放,必須通過DeleteGlobalRef()手動釋放 - (*env)->DeleteGlobalRef(env, g_cls_string)。他可以跨方法和跨線程使用,而且不會被自動釋放直到你手動call了DeleteGlobalRef().每一個JNI引用被建立的時候,除了他指向的JVM對象,他本身也會消費一定的空間,是以需要有一定的sense在不需要他的時候手動DeleteGlobalRef()掉他

弱全局引用:

通過NewWeakGlobalRef(),參數為局部引用或者全局引用,不會阻止GC對其回收,他跟全局引用一樣也可以跨方法,跨線程使用,但是因為帶有全局的屬性,不會自動釋放。在JVM認為他可以回收的時候(記憶體緊張)進行回收而釋放。或者你可以顯式調用DeleteWeakGlobalRef手動釋放,(*env)->DeleteWeakGlobalRef(env, g_cls_string)。跨線程和跨方法屬性跟全局引用類似,但跟全局引用不同的一點是,弱引用不會阻止GC回收他的對象,是以在使用之前需要通過env->IsSameObject(xxx, NULL)來保證此時的對象還有效

JNI局部引用,全局引用,弱全局引用(Weak Global Reference)介紹

同樣,當我們不再需要一個弱全局引用的時候,也要調用DeleteWeakGlobalRef()來釋放他,因為雖然JVM會釋放他所指向的對象,但是弱引用本身在引用表中所占的記憶體也是需要被釋放的,是以需要通過這個函數

繼續閱讀