【原创】JNI使用的总结

最近在JNI的项目,由于第一次使用,查了一些资料,现总结如下:

参考资料:

1、http://docs.oracle.com/javase/6/docs/technotes/guides/jni/index.html

2、http://blog.csdn.net/fightspirite/article/details/6859829

3、http://blog.csdn.net/super005/article/details/6387575

4、http://www.cr173.com/html/17867_1.html

5、http://www.cnblogs.com/codc-5117/archive/2012/09/06/2672815.html

6、http://www.cnblogs.com/codc-5117/archive/2012/09/06/2672833.html

7、http://blog.chinaunix.net/uid-23065002-id-3077584.html

8、http://blog.csdn.net/zgyulongfei/article/details/7409441

总结一:关于JNIEnv和JavaVM

native程序中频繁使用JNIEnv*和JavaVM*。而C和C++代码使用JNIEnv*和JavaVM*这两个指针的做法是有区别的,网上大部分代码都使用C++,基本上找不到关于C和C++在这个问题上的详细叙述。

在C中:

使用JNIEnv* env   要这样      (*env)->方法名(env,参数列表)

使用JavaVM* vm    要这样       (*vm)->方法名(vm,参数列表)

 

在C++中:

使用JNIEnv* env   要这样      env->方法名(参数列表)
  
使用JavaVM* vm   要这样       vm->方法名(参数列表)

 

上面这二者的区别是,在C中必须先对env和vm间接寻址(得到的内容仍然是一个指针),在调用方法时要将env或vm传入作为第一个参数。C++则直接利用env和vm指针调用其成员。

总结二:"char *"与"java string"的互相转换

1.jstring转换为C风格字符串

char* test = (char*)(*env)->GetStringUTFChars(env,jstring,NULL);

使用完毕后,应调用:

(*env)->ReleaseStringUTFChars(env,jstring, test);

释放资源。

2.C风格字符串转换为jstring

char charStr[50];

jstring jstr;

jstr = env ->NewStringUTF(charStr);

3.C语言中获取的一段char*的buffer传递给Java

在jni中new一个byte数组,然后使用

(*env)->SetByteArrayRegion(env,bytearray, 0, len, buffer)

操作将buffer拷贝到数组中。

这种方式主要是针对buffer中存在“\0”的情况,如果以C风格字符串的方式读入,就会损失“\0”之后的字符。

4.数组操作

数组操作的相关函数列表如下:

JNI函数                    功能 

GetArrayLength             返回数组中的元素数 

NewObjectArray             创建一个指定长度的原始数据类型数组 

GetObjectArrayElement      返回Object数组的元素 

SetObjectArrayElement      设置Object数组的元素 

GetObjectArrayRegion       将原始数据类型数组中的内容拷贝到预先分配好的内存缓存中 

SetObjectArrayRegion       设置缓存中数组的值 

ReleaseObjectArrayRegion   释放GetObjectArrayRegion分配的内存 

对int,char等基本数据类型的数组操作,将相关Object名称替换为对应基本数据类型名称即为相关函数。

数组操作的方法选择基于使用者的需求而定,如果使用者需要在内存中拷贝数组并对其进行操作那么一般使用GetObjectArrayRegion和SetObjectArrayRegion函数,否则一般使用SetObjectArrayElement和GetObjectArrayElement函数。

写一个简单的例子,分享一下:

http://pan.baidu.com/s/11MThi

总结三:常用的字符串类型处理的函数:

1const char* GetStringUTFChars (jstring string,jboolean* isCopy)

返回指向字符串UTF编码的指针,如果不能创建这个字符数组,返回null。这个指针在调用ReleaseStringUTFChar()函数之前一直有效。 参数:

string Java字符串对象 

isCopy 如果进行拷贝,指向以JNI_TRUE填充的jboolean,否则指向以JNI_FALSE填充的jboolean。

2void ReleaseStringUTFChars(jstring str, const char* chars)

通知虚拟机本地代码不再需要通过chars访问Java字符串。 

参数:

string Java字符串对象 

chars 由GetStringChars返回的指针

3)   jstring NewStringUTF(const char *utf)

返回一个新的Java字符串并将utf内容拷贝入新串,如果不能创建字符串对象,返回null。通常在反值类型为string型时用到。 

参数:

utf UTF编码的字符串指针,对于数值型参数,在C/C++中可直接使用

参数:

array 数组对象 

isCopy 如果进行拷贝,指向以JNI_TRUE填充的jboolean,否则指向以JNI_FALSE填充的jboolean。 

例如:jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy)

4void ReleaseXxxArrayElements(xxxArray array,xxx *elems, jint mode)

通知虚拟机不再需要从GetXxxArrayElements得到的指针。 

参数:

array 数组对象 

elems 不再需要的指向数组元素的指针 

mode 0=在更新数组元素后释放elems缓冲器 

JNI_COMMIT=在更新数组元素后不释放elems缓冲器 

JNI_ABORT=不更新数组元素释放elems缓冲器 

例如:void ReleaseBooleanArrayElements(jbooleanArray array,jboolean *elems, jint mode)

5)   xxxArray NewXxxArray(jsize len)

产生一个新的数组,通常在反值类型为数组型时用到。

参数:

len 数组中元素的个数。 

例如:jbooleanArray NewBooleanArray(jsize len)

 

总结四:JNI内存泄露

一:

  在c++中new的对象,如果不返回java,必须用release掉,否则内存泄露。包括NewStringUTF,NewObject等。

  如果返回java不必release,java会自己回收。

  

...

jstring jstr = env->NewStringUTF((*p).sess_id);

  ...

env->DeleteLocalRef( jstr); /* 必须调用,否则泄露 */

  ...

jobject jobj = env->NewObject(clazz,midInit); /* 有返回,不用管 */

return jobj;

 

二:

  jstring jstr = (jstring)env->CallObjectMethod(authenRequest, mid_authenReq_getSdId_S);

  env->GetStringUTFRegion(jstr,0,env->GetStringLength(jstr),authenReq.sd_id);

 

  当jstr是null时,env->GetStringLength(jstr)会出错,导致jvm崩溃

三:

    在 JNI 编程时,正确控制 JNI Local Reference 的生命期。

    如果需要创建过多的 Local Reference,那么在对被引用的 Java 对象操作结束后,需要调用 JNI function(如 DeleteLocalRef()),及时将 JNI Local Reference 从 Local Ref 表中删除,以避免潜在的内存泄漏。

 

----------- 2013-10-09

posted @ 2016-04-12 20:40  xiaoleisme  阅读(661)  评论(0编辑  收藏  举报