[JNI] must I release java strings?

S

Sasha

Hi all,

do you need to release java strings (or, for that matter, any java object)
you create in JNI code? I'm trying to find out why a particular piece of
code is crashing when I exit the program (long after the JNI code has
executed).

Of course, C-style strings need to be released. But do I need to tell Java
that I don't need to reference an object any more? Or will it just figure it
out and garbage collect an object automatically?

My code looks something like this:

/* call a logging method in the parent object */
void LogMessage(JNIEnv *environment, jobject instance, const char *message,
jint level)
{
/* convert string to java string */
jstring jsMessage = environment->NewStringUTF(message);

/* log da message */
jclass bridgeClass = environment->FindClass(BRIDGE_CLASS);
if (bridgeClass == 0)
return;
jmethodID log = environment->GetMethodID(bridgeClass, "log",
BRIDGE_LOG_SIG);
if (jmethodID == 0)
return;

jthrowable exc = environment->ExceptionOccurred();
if (exc) {
environment->ExceptionClear();
/* propagate exc */
environment->Throw(exc);
}

environment->CallVoidMethod(instance, log, jsMessage, level);

exc = environment->ExceptionOccurred();
if (exc) {
environment->ExceptionClear();
/* propagate exc */
environment->Throw(exc);
}
}

Any help would be greatly appreciated.

Regards,

Sasha.
 
G

Gordon Beaton

do you need to release java strings (or, for that matter, any java
object) you create in JNI code? I'm trying to find out why a
particular piece of code is crashing when I exit the program (long
after the JNI code has executed).

That would tend to indicate that you have a pointer error of some kind
in your code.
Of course, C-style strings need to be released. But do I need to
tell Java that I don't need to reference an object any more? Or will
it just figure it out and garbage collect an object automatically?

You normally don't need to release any java objects explicitly in
native code. The same rules of reachability apply, regardless of
whether you create the strings in java or native code. After you
return from the native method, all objects that you have not passed
"back to java" or created global references to, will become eligible
for garbage collection.
My code looks something like this:

Strictly speaking there is nothing wrong with the example you posted,
however there is little point in checking for exceptions in those
particular places, because if an exception had occurred then the
previous check for NULL (that you incorrectly spelled 0) and
corresponding return statements would prevent you from reaching
ExceptionOccurred(). In either case you don't need to catch and
rethrow exceptions, they will propagate upwards/outwards anyway.

/gordon
 
S

Sasha

Gordon,

thanks a stack for such a prompt response.

Incidently, if I want to return null back to Java, then I just return NULL,
(i.e. 0), yes? This is from a method which returns an object.

Cheers,

Sasha.
 
S

Sudsy

Sasha said:
Hi all,

do you need to release java strings (or, for that matter, any java object)
you create in JNI code? I'm trying to find out why a particular piece of
code is crashing when I exit the program (long after the JNI code has
executed).

I thought I knew the answer to this question "off the top of my head"
but went to java.sun.com for the defintive word:

"Note: When your native code is finished using the UTF-8 string, it
MUST call ReleaseStringUTFChars. ReleaseStringUTFChars informs the VM
that the native method is finished with the string so that the VM can
free the memory taken by the UTF-8 string. Failing to call
ReleaseStringUTFChars results in a memory leak. This will ultimately
lead to system memory exhaustion."

(emphasis added)

This is from the Java Native Interface section of the Java Tutorial.
 
G

Gordon Beaton

I thought I knew the answer to this question "off the top of my head"
but went to java.sun.com for the defintive word:

"Note: When your native code is finished using the UTF-8 string, it
MUST call ReleaseStringUTFChars.

Yes, but it doesn't have anything to do with releasing the Java
strings the OP was asking about.

A prerequisite for using ReleaseStringUTFChars() is that you
previously called GetStringUTFChars(), which isn't the case here.

/gordon
 
S

Sudsy

Yes, but it doesn't have anything to do with releasing the Java
strings the OP was asking about.

A prerequisite for using ReleaseStringUTFChars() is that you
previously called GetStringUTFChars(), which isn't the case here.

/gordon

From the immediately subsequent paragraph in the tutorial:

"The native method can also construct a NEW string using the JNI
function NewStringUTF. The following lines of code from
Java_Prompt_getLine show this:

...
scanf("%s", buf);
return (*env)->NewStringUTF(env, buf);
}"

(emphasis added)

It's still a new string, even though it wasn't created by
GetStringUTFChars. I believe that it DOES directly apply to
the question posed by the OP and the jstring SHOULD be freed
with ReleaseStringUTFChars. Perhaps you have some definitive
proof of the converse?
 
G

Gordon Beaton

scanf("%s", buf);
return (*env)->NewStringUTF(env, buf);
It's still a new string, even though it wasn't created by
GetStringUTFChars. I believe that it DOES directly apply to
the question posed by the OP and the jstring SHOULD be freed
with ReleaseStringUTFChars. Perhaps you have some definitive
proof of the converse?

GetStringUTFChars() doesn't create a new Java string (jstring), it
extracts a C-style char* from an existing jstring.
ReleaseStringUTFChars() is later used for releasing the char*, not the
jstring.

From the documentation in the JNI spec (not the tutorial) for
GetStringUTFChars():

"This array is valid until it is released by ReleaseStringUTFChars()"

From the documentation for ReleaseStringUTFChars():

"The utf argument is a pointer derived from string using
GetStringUTFChars()."

....which would seem to indicate that ReleaseStringUTF() should not be
invoked with any other kinds of pointers, and that the pointer is
derived from the string (not the other way around). Also the
documentation for NewStringUTF() does not mention
ReleaseStringUTFChars() at all.

Finally, ReleaseStringUTFChars() uses os::free(p) to dispose of the
char*, while NewStringUTF() does not require that the char* be
allocated dynamically. In your example, it would be extremely
unfortunate if buf were declared like this and ReleaseStringUTFChars()
later called:

char buf[512];

/gordon
 
S

Sudsy

<Gordon forces me to reread the documentation at this point>

Mea culpa. It appears that NewStringUTF() creates a new
java.lang.String which should be created on the heap,
subject to all the usual eligibility rules for garbage
collection. I still haven't found explicit mention of
that in the documentation, but the wording would seem
to indicate that it is the case.
So no, you wouldn't want to free() it. Oops!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
KetoBurn
Top