- void myJniFunc(JNIEnv *env,jclass clazz,jobjectArray items) {
- int count = 10;
- struct MyObj *myObjArray = (struct MyObj*)malloc(sizeof(struct MyObj) * count);
- for (i = 0; i < count; i++) {
- jobject obj = (*env)->GetObjectArrayElement(env,items,i);
- jfieldID fieldId = ...;
- jstring jstr = (*env)->GetObjectField(env,obj,fieldId);
- myObjArray[i].name = (*env)->GetStringUTFChars(env,jstr);
- (*env)->DeleteLocalRef(env,obj);
- // Location A
- }
- // some code which will use myObjArray
- process(count,myObjectArray);
- // Location B
- }
通过JNI doc,GetStringUTFChars返回的数组应该使用
- (*env)->ReleaseStringUTFChars(env,jstr,myObjArray[i].name);
- (*env)->ReleaseLocalRef(env,jstr);
>如果我在位置A释放返回的数组,则myObjArray.name将为空
>如果我在位置B释放返回的数组,因为我将保留jstring的引用,那么“将失败添加到JNI本地ref表(有512个条目)”将会发生
我的问题是:
如果我想正确释放jstring,我该怎么办?
解决方法
由于您希望保留字符串的字节以便在循环外使用,因此需要复制字节,因为在释放字符串引用之前必须释放JVM的固定(或临时副本)(GetStringUTFChars)(ReleaseStringUTFChars).
所以循环中字符串的顺序必须是:
> GetObjectField
> GetStringUTFChars
>制作自己的副本
> ReleaseStringUTFChars
> DeleteLocalRef
注意:使用GetStringUTFChars,您将获得指向Java String的已修改UTF-8编码的指针.这里有两点:
>您的代码应该能够处理修改后的UTF-8编码字符. (它每个字符有一到六个字节,并以一种特殊的方式编码NUL.)
>文档没有说明数组是否以0结尾.您可以使用GetStringUTFLength来获取修改后的UTF-8编码中的字节数 – 不计算任何0终止符. (各种JNI实现和The Book都同意该阵列以0结尾.)如果您想使用终结器制作自己的副本,请务必为终结器添加空间.
如果您更喜欢使用UTF-16编码,请使用GetStringChars和GetStringLength.在这种情况下,阵列绝对不会终止;它使用内部计数和字符串字节而不进行任何转换.
或者,如果您想更改字符集,比如真正的“UTF-8”,“ASCII”,“CP437”或“Windows-1252”或您的代码可以处理的其他内容,请使用String.getBytes重载或Charset类.如果要控制如何处理目标字符集中不支持的字符,请使用Charset类.