内存释放

这个是JNI开发必须得注意的,因为JNI开发不像java开发,在java中我们基本上不用去考虑内存释放的问题,因为java的垃圾回收机制会处理这类问题,虽然说JNI层的Local Reference的生命周期持续到一个Native Method的结束,当Native Method返回时Java Heap中的对象不再被持有,也将会被GC回收,但是在JNI中如果我们使用了过多的局部引用,但是未及时释放这些内存,可能会导致出现局部引用表溢出的错误local reference table overflow (max=512),这个错误和安卓中的OOM类似,都是内存不够导致程序crash。之所以会出现局部引用表溢出的错误,是因为当代码从java层进入JNI层的时候虚拟机会创建一个local reference table来存储局部引用,但是这张表的大小是有限制的,一般为512项,当在JNI层创建一个局部引用时就会将其添加到该表中,如果创建的局部引用的个数超过了local reference table的大小就会出现local reference table overflow (max=512)这个错误, 因此当我们创建了一个局部引用时在其不使用的地方最好释放掉,尤其是当我们在for/while循环中创建了局部引用的时候,一定要注意局部引用的释放问题。 一般下面这些API获取的对象需要调用对应的API释放内存。因为这些API的调用会创建一个局部引用(不是说创建了局部引用就一定要释放掉,而是说这是一种好的习惯,能够避免出现局部引用表溢出的错误)

对象创建:

jclass FindClass(JNIEnv *env, const char *name)
jclass GetObjectClass(JNIEnv *env, jobject obj)
jobject GetObjectField(JNIEnv *env, jobject obj,jfieldID fieldID)
jobject CallObjectMethod(JNIEnv *env,jobject obj,jmethodID methodID)

从上述这些API的返回值类型可以看到这些API都会返回一个对象,对于此类API创建的对象统一调用void DeleteLocalRef(JNIEnv *env, jobject localRef)来释放对象

字符串的创建与释放

const char * GetStringUTFChars(JNIEnv *env, jstring string,jboolean *isCopy)对应—>void ReleaseStringUTFChars(JNIEnv *env, jstring string,const char *utf);
jstring NewStringUTF(JNIEnv *env, const char *bytes)

NewStringUTF调用void DeleteLocalRef(JNIEnv *env, jobject localRef)来释放,因为字符串本身是一种特殊的对象类型

数组系列对象创建与释放

NativeType *GetArrayElements(JNIEnv *env,ArrayType array, jboolean *isCopy)对应—>void ReleaseArrayElements(JNIEnv *env,ArrayType array, NativeType *elems, jint mode)

调用对应的数组类型释放函数,如GetByteArrayElements则调用ReleaseByteArrayElements,GetIntArrayElements则调用ReleaseIntArrayElements

调用GetObjectField函数获取对象后在使用前最好进行下判空操作

在JNI中使用GetObjectField函数获取对象很容易出现获取对象失败的情况,因此在使用该函数得到对象后在使用前最好进行下判空操作,像下面这样:

jobjectArray signatures = (jobjectArray)m_env->GetObjectField(obj_signPkgInfo, fieldID_signatures);
if (signatures != NULL)
{
//todo...
}