释放双眼,带上耳机,听听看~!
今天,简单讲讲android 如何释放在jni新建得 结构体等资源。
因为android里是自动释放资源的,所以之前没有注意这一点,后来查找资料才发现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)。
下面举一些具体的例子:
1.FindClass
例如,
jclass ref= (env)->FindClass("java/lang/String");
env->DeleteLocalRef(ref);
2.NewString/ NewStringUTF/NewObject/NewByteArray
例如,
jstring (*NewString)(JNIEnv*, const jchar*, jsize);
const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);
void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);
jstring (*NewStringUTF)(JNIEnv*, const char*);
const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);
void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);
使用env->DeleteLocalRef(ref); 释放资源。
3.GetObjectField/GetObjectClass/GetObjectArrayElement
jclass ref = env->GetObjectClass(robj);
env->DeleteLocalRef(ref);
4.GetByteArrayElements和GetStringUTFChars
jbyte* array= (*env)->GetByteArrayElements(env,jarray,&isCopy);
(*env)->ReleaseByteArrayElements(env,jarray,array,0);
const char* input =(*env)->GetStringUTFChars(env,jinput, &isCopy);
(*env)->ReleaseStringUTFChars(env,jinput,input);
5.NewGlobalRef/DeleteGlobalRef
jobject ref= env->NewGlobalRef(customObj);
env->DeleteGlobalRef(customObj);
这里可能有一些需要注意的,如果新建的数组,结构体作为返回值给android,android可能会自动释放,不需要jni再进行释放。这个大家可以去查找资料看看,我对这些也不很清楚。
android jni 释放资源就讲完了。
就这么简单。