ReleaseStringUTF不仅仅是释放内存吗?

时间:2010-03-12 22:02:51

标签: c java-native-interface memory-management

考虑以下C代码段。

第1部分:

char * getSomeString(JNIEnv *env, jstring jstr) {
   char * retString;
   retString = (*env)->GetStringUTFChars(env, jstr, NULL);
   return retString;
}

void useSomeString(JNIEnv *env, jobject jobj, char *mName) {
   jclass cl = (*env)->GetObjectClass(env, jobj);
   jmethodId mId = (*env)->GetMethodID(env, cl, mName, "()Ljava/lang/String;");
   jstring jstr = (*env)->CallObjectMethod(env, obj, id, NULL);

   char * myString = getSomeString(env, jstr);

/* ... use myString without modifing it */

   free(myString);
}

因为myString在useSomeString中被释放,所以我认为我没有创建内存泄漏;但是,我不确定。 JNI规范特别要求使用ReleaseStringUTFChars。由于我从GetStringUTFChars获取了一个C风格的'char *'指针,我相信内存引用存在于C堆栈而不是JAVA堆中,因此它没有被Garbage Collected的危险;但是,我不确定。

我知道如下更改getSomeString会更安全(也许更可取)。

第2部分:

char * getSomeString(JNIEnv *env, jstring jstr) {
   char * retString;
   char * intermedString;

   intermedString = (*env)->GetStringUTFChars(env, jstr, NULL);
   retString = strdup(intermedString);
   (*env)->ReleaseStringUTFChars(env, jstr, intermedString);
   return retString;
}

由于我们的'过程',我需要建立一个论证,说明为什么段2中的getSomeString优于段1。

是否有人知道任何详细说明GetStringUTFChars和ReleaseStringUTFChars与分配内存或执行了哪些(如果有)额外簿记(即创建Java堆的本地参考指针等)的行为的文档或参考文献。无视簿记的具体后果是什么。

提前致谢。

2 个答案:

答案 0 :(得分:4)

您无需关心实施细节;如果GetStringUTFChars的文档说你必须使用ReleaseStringUTFChars,那么就这样做吧。

大多数库提供自己的功能来释放他们分配的内存,因为他们的CRT / heap / ...可能与你的应用程序不同,所以如果你试图免费使用你的 他们的指针,你可能会在你身边获得相当于双倍免费的指针,而在库方面则会出现内存泄漏。

我会再说一遍:不依赖于实施细节。图书馆作者相信每个人都遵循他们的指导方针,所以即使今天的免费可能有效,明天他们也可能决定使用另一个堆/分配器/ ......如果你遵循他们的指导方针,你会体验到没问题,因为他们会相应地更新ReleaseStringUTFChars,但如果您依赖于该实现细节,您的应用程序可能会突然开始死亡或遇到内存泄漏。

答案 1 :(得分:1)

我们最终发现了什么。

链接Java和C的应用程序将共享堆空间。这意味着在事件的C端分配的任何内存都不能在为Java保留的堆部分中分配malloc(et.al.)。但是,由JNI函数本身分配的任何内存可能会也可能不会在堆的Java端分配空间(它是JNI的实现细节)。这留下了两种可能性:1)从堆的C端分配内存,其中调用free不会产生任何不良影响; 2)从Java端分配内存将打开GC在C侧完成之前回收内存的可能性。面对这种不确定性,最安全的方法是使用malloc显式分配新空间,释放JNI内存,并在不再需要新分配的内存时自由调用。

我要感谢Matteo Italia对此的帮助。