1. 程式人生 > >JNI 資源釋放

JNI 資源釋放

JNI 程式設計實現了 native code 和 Java 程式的互動,因此 JNI 程式碼程式設計既遵循 native code 程式語言的程式設計規則,同時也遵守 JNI 程式設計的文件規範。在記憶體管理方面,native code 程式語言本身的記憶體管理機制依然要遵循,同時也要考慮 JNI 程式設計的記憶體管理。

本章簡單概括 JNI 程式設計中顯而易見的記憶體洩漏。從 native code 程式語言自身的記憶體管理,和 JNI 規範附加的記憶體管理兩方面進行闡述。

Native Code 本身的記憶體洩漏

JNI 程式設計首先是一門具體的程式語言,或者 C 語言,或者 C++,或者彙編,或者其它 native 的程式語言。每門程式語言環境都實現了自身的記憶體管理機制。因此,JNI 程式開發者要遵循 native 語言本身的記憶體管理機制,避免造成記憶體洩漏。以 C 語言為例,當用 malloc() 在程序堆中動態分配記憶體時,JNI 程式在使用完後,應當呼叫 free() 將記憶體釋放。總之,所有在 native 語言程式設計中應當注意的記憶體洩漏規則,在 JNI 程式設計中依然適應。

Native 語言本身引入的記憶體洩漏會造成 native memory 的記憶體,嚴重情況下會造成 native memory 的 out of memory。

Global Reference 引入的記憶體洩漏

JNI 程式設計還要同時遵循 JNI 的規範標準,JVM 附加了 JNI 程式設計特有的記憶體管理機制。

JNI 中的 Local Reference 只在 native method 執行時存在,當 native method 執行完後自動失效。這種自動失效,使得對 Local Reference 的使用相對簡單,native method 執行完後,它們所引用的 Java 物件的 reference count 會相應減 1。不會造成 Java Heap 中 Java 物件的記憶體洩漏。

而 Global Reference 對 Java 物件的引用一直有效,因此它們引用的 Java 物件會一直存在 Java Heap 中。程式設計師在使用 Global Reference 時,需要仔細維護對Global Reference 的使用。如果一定要使用 Global Reference,務必確保在不用的時候刪除。就像在 C 語言中,呼叫 malloc() 動態分配一塊記憶體之後,呼叫 free()釋放一樣。否則,Global Reference 引用的 Java 物件將永遠停留在 Java Heap 中,造成 Java Heap 的記憶體洩漏。

1、什麼需要釋放? 

什麼需要什麼呢 ? JNI 基本資料型別是不需要釋放的 , 如 jint , jlong , jchar 等等 。 我們需要釋放是引用資料型別,當然也包括陣列家族。如:jstring,jobject ,jobjectArray,jintArray 等等。

當然,大家可能經常忽略掉的是 jclass ,jmethodID , 這些也是需要釋放的哦

2、如何去釋放?

1)      釋放String

jstring jstr = NULL;

char* cstr = NULL;

//呼叫方法

jstr = (*jniEnv)->CallObjectMethod(jniEnv, mPerson, getName);

cstr = (char*) (*jniEnv)->GetStringUTFChars(jniEnv,jstr, 0);

__android_log_print(ANDROID_LOG_INFO, "JNIMsg", "getName  ---- >  %s",cstr );

//釋放資源

(*jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, cstr);

(*jniEnv)->DeleteLocalRef(jniEnv, jstr);

2)      釋放 類 、物件、方法

(*jniEnv)->DeleteLocalRef(jniEnv, XXX);

“XXX” 代表 引用物件

3)      釋放 陣列家族

jobjectArray arrays = NULL;

jclass jclsStr = NULL;

jclsStr = (*jniEnv)->FindClass(jniEnv, "java/lang/String");

arrays = (*jniEnv)->NewObjectArray(jniEnv, len, jclsStr, 0);

(*jniEnv)->DeleteLocalRef(jniEnv, jclsStr);  //釋放String類

(*jniEnv)->DeleteLocalRef(jniEnv, arrays); //釋放jobjectArray陣列

native method 呼叫 DeleteLocalRef() 釋放某個 JNI Local Reference 時,首先通過指標 p 定位相應的 Local Reference 在 Local Ref 表中的位置,然後從Local Ref 表中刪除該 Local Reference,也就取消了對相應 Java 物件的引用(Ref count 減 1)。