我的应用程序需要使用jni。逻辑如下:
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 文档,GetStringUTFChars 返回的数组应该使用
(*env)->ReleaseStringUTFChars(env, jstr, myObjArray[i].name);
(*env)->ReleaseLocalRef(env, jstr);
- 如果我在位置 A 释放返回的数组,则 myObjArray.name 将为空
- 如果我在位置 B 释放返回的数组,因为我将保留 jstring 的引用,那么将会发生“无法添加到 JNI 本地引用表(有 512 个条目)”
我的问题是:
如果我想正确释放jstring该怎么办?
由于您的循环正在创建本地引用 (GetObjectField),因此您需要在循环中释放它 (DeleteLocalRef),否则您将遇到本地引用的限制。您必须在两次调用之间完全处理 Java 字符串。
由于您希望保留字符串的字节以供在循环之外使用,因此需要复制这些字节,因为必须在释放字符串引用之前释放 JVM 的固定(或临时副本)(GetStringUTFChars) (ReleaseStringUTFChars)。
因此循环内字符串的顺序必须是:
GetObjectField
GetStringUTFChars
- 制作你自己的副本
ReleaseStringUTFChars
DeleteLocalRef
注:与GetStringUTFChars
您将获得一个指向 Java 字符串的修改后的 UTF-8 编码的指针。这里有两点:
- 您的代码应该能够处理修改后的 UTF-8 编码字符。 (它每个字符有 1 到 6 个字节,并以一种特殊的方式对 NUL 进行编码。)
- 文档没有说明数组是否以 0 结尾。您可以使用
GetStringUTFLength
获取修改后的 UTF-8 编码中的字节数,不包括任何 0 终止符。 (各种 JNI 实现和The Book https://rads.stackoverflow.com/amzn/click/com/0201325772请同意该数组以 0 结尾。)如果您想使用终止符制作自己的副本,请务必为终止符添加空间。
如果您想使用 UTF-16 编码,请使用GetStringChars
and GetStringLength
。在这种情况下,数组肯定没有终止;它使用内部计数和字符串字节,无需任何转换。
或者,如果您想更改字符集,例如真正的“UTF-8”、“ASCII”、“CP437”或“Windows-1252”或您的代码可以处理的其他字符集,请使用String.getBytes
过载或Charset
班级。使用Charset
如果您想控制如何处理目标字符集中不支持的字符,请使用 .class 。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)