Consider the following C code segments.
Segment 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 j开发者_如何学Cstr = (*env)->CallObjectMethod(env, obj, id, NULL);
char * myString = getSomeString(env, jstr);
/* ... use myString without modifing it */
free(myString);
}
Because myString is freed in useSomeString, I do not think I am creating a memory leak; however, I am not sure. The JNI spec specifically requires the use of ReleaseStringUTFChars. Since I am getting a C style 'char *' pointer from GetStringUTFChars, I believe the memory reference exists on the C stack and not in the JAVA heap so it is not in danger of being Garbage Collected; however, I am not sure.
I know that changing getSomeString as follows would be safer (and probably preferable).
Segment 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;
}
Because of our 'process' I need to build an argument on why getSomeString in Segment 2 is preferable to Segment 1.
Is anyone aware of any documentation or references which detail the behavior of GetStringUTFChars and ReleaseStringUTFChars in relation to where memory is allocated or what (if any) additional bookkeeping is done (i.e. local Reference Pointer to the Java Heap being created, etc). What are the specific consequences of ignoring that bookkeeping.
Thanks in advance.
You don't need to care about implementation details; if the documentation of GetStringUTFChars says you that you must use ReleaseStringUTFChars, you do it, period.
Most libraries provide their own functions to free the memory they allocate because their CRT/heap/... may be different than the one of your application, so if you try to use your free on their pointers you may get on your side the equivalent of a double free, and on the library side a memory leak.
I'll say it again: do not rely on implementation details. The library authors are confident that everyone follows their guidelines, so even if a free today may work, tomorrow they may decide to use another heap/allocator/... If you followed their guidelines you'd experience no problem, because they would have updated ReleaseStringUTFChars accordingly, but if you relied on that implementation detail all of a sudden your application may start do die or to experience memory leaks.
What we finally discovered.
An application linking Java and C will share the heap space. This implies any memory allocated on the C side of things with malloc (et. al.) can not be allocated in the section of the heap reserved for Java. However, any memory allocated by the JNI functions themselves may or may not allocate space on the Java side of the heap (it being an implementation detail of JNI). This leaves two possibilities: 1) memory is allocated from the C side of the heap where calling free leaves no ill effects; 2) memory is allocated from the Java side will opens the possibility the memory is reclaimed by the GC before the C side is done with it. In the face of this uncertainty the safest course is to explicitly allocate new space with malloc, release the JNI memory, and call free whenever the newly allocated memory is no longer needed.
I'd like to thank Matteo Italia for his assistance in this.
精彩评论