jni未釋放資源問題。Failed adding to JNI local ref table (has 512 entries)

轉載於http://www.cnblogs.com/luxiaofeng54/archive/2011/08/21/2147822.html


基於 Android NDK 的學習之旅-----資源釋放

        做上一個項目的時候因爲與C引擎交互頻繁,有時候會突然莫名其妙的的整個應用程序直接掛掉。因爲我是學Java 開始的,所以對主動釋放內存沒多大概念(GC直接幫忙回收),後查詢原因才知道是因爲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)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章