Java Native Interface(JNI)的空間(參考)管理
Java是通過垃圾回識訓制回收記憶體,C/C++是通過malloc,free,new,delete手動管理空間,那么在JNI層,同時存在Java和C/C++的空間時,該如何進行空間的管理呢?本文參考Oracle的官方檔案,對JNI層中空間的管理進行說明,明確哪些內容需要手動呼叫Delete,哪些不需要手動呼叫,
一、全域參考(Global References)
全域參考的生命周期(Lifetime),需要主動通過函式呼叫進行申請和釋放,native函式執行完畢后,該空間可繼續使用,
函式原型
// 創建全域參考
jobject NewGlobalRef(JNIEnv *env, jobject obj);
// 洗掉全域參考
void DeleteGlobalRef(JNIEnv *env, jobject globalRef);
二、區域參考(Local References)
區域參考的生命周期(Lifetime),與呼叫的native函式一致,當native函式return時,區域參考將會被自動釋放,該區域參考占用的空間是JVM的資源,
由于native函式用于存放區域參考的空間是固定的,如果過度的創建區域參考,不加以控制,可能會出現空間不足,程式拋出Out Of Memory(OOM)例外的問題,如果該區域參考已經使用完畢,應盡量手動呼叫DeleteLocalRef,提前釋放空間,避免OOM,
函式原型
// 創建全域參考
jobject NewLocalRef(JNIEnv *env, jobject obj);
// 洗掉全域參考
void DeleteLocalRef(JNIEnv *env, jobject localRef);
// 主動設定可創建的區域參考的數量
jint EnsureLocalCapacity(JNIEnv *env, jint capacity);
// 創建一個區域參考的幀,并指定可創建的區域參考的數量,
jint PushLocalFrame(JNIEnv *env, jint capacity);
// 釋放當前區域參考的幀,釋放全部本地參考,
// 可以通過引數result,將被PopLocalFrame釋放的參考轉移到上一層的區域參考幀中
jobject PopLocalFrame(JNIEnv *env, jobject result);
特殊說明
- 在JDK/JRE 1.1版本中,提供了
DeleteLocalRef函式, - 在JDK/JRE 1.2版本中,提供了
EnsureLocalCapacity,PushLocalFrame,PopLocalFrame,NewLocalRef函式,支持更加復雜的區域參考生命周期能力,
三、弱全域參考(Weak Global Reference)
區別于全域參考(Global References),該參考并不會增加該參考的參考計數,
即持有弱全域參考,不會干預垃圾回識訓制(GC)對于該記憶體的回收,適用于生命周期短的物件,持有生命周期長的參考,
全域參考可以通過jboolean IsSameObject(JNIEnv *env, jobject ref1, jobject ref2); 函式,引數為被判定物件和NULL來判斷物件是否存在,如果回傳JNI_TRUE判定該弱參考指向的物件是否已經被釋放,
使用弱全域參考時,可能會出現執行一半,參考被GC回收的情況,所以需要在使用弱全域參考之前,提供NewLocalRef或者NewGlobalRef,將弱參考轉換為強參考,確保GC不會對該空間進行回收,
四、常見問題
1、在native函式中,直接return一個jstring或者其他jobject,是否會有記憶體泄漏問題?
如果直接return的物件是區域參考(Local Reference),則不會發生記憶體泄漏問題,
區域參考在native函式執行完畢后,會根據區域參考表(Local Reference Table)進行空間的釋放,
當然,手動執行DeleteLocalRef函式進行提前釋放,也不會產生問題,
2、什么情況下可能會出現記憶體泄漏?
1)創建的全域參考(Global Reference),未呼叫Delete函式進行回收,導致該物件參考計數無法歸零,
2)兩個物件互相持有對方的強參考,例如A持有B參考,B和C互相持有對方的參考,當A釋放B參考時,GC發現C依然持有B的參考,則不會釋放B,與此同時,GC也發現B持有C的參考,則不會釋放C,導致B和C與其他參考脫離,形成孤島,這塊記憶體將無法使用,也無法被釋放,
3、呼叫NewString和NewStringUTF時,是否需要釋放?
NewString和NewStringUTF函式創建的空間屬于區域參考(Local Reference),可以等待native函式執行完畢后自動回收,也可以在使用完畢(后續不會再訪問)后,直接進行Delete釋放,
但是需要注意,如果通過GetStringChars,GetStringCritical或者GetStringUTFChars獲取了jstring中的char* 空間,則需要使用對應的ReleaseStringChars,ReleaseStringCritical或者ReleaseStringUTFChars釋放該char* 空間,
參考文章
- JNI Functions (oracle.com)

本文來自博客園,作者:GiraKoo
轉載請注明原文鏈接:https://www.cnblogs.com/girakoo/p/17411752.html
友情鏈接:GiraKoo 博客園 CSDN 稀土掘金
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/552793.html
標籤:Java
上一篇:實驗三 Java類的繼承與派生
下一篇:返回列表
