android jni 释放资源

释放双眼,带上耳机,听听看~!

今天,简单讲讲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 jobjectArrayjintArray
等等。

当然,大家可能经常忽略掉的是 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 释放资源就讲完了。

就这么简单。

人已赞赏
Android文章

android BufferedOutputStream的使用

2020-4-8 20:18:07

Android文章

android jni jstring 转 char*

2020-4-8 21:34:04

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索