Search code examples
javaandroidreferencegarbage-collectionjava-native-interface

Correct usage of DeleteLocalRef in JNI


Here is the sample jni method where I create a string and return it to the calling java method:

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    char test[100];
    sprintf(test, "Test%03d.txt", rand()/100);
    jstring returnVal = (*env)->NewStringUTF(env, test);
    (*env)->DeleteLocalRef(env,returnVal);
    return returnVal;
}

I was expecting the jstring to be invalid in the calling java method since I deleted the local reference. But the reference is still valid. I explicitly called System.gc() to see whether the GC clears it, but it didn't happen.

According to this: http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html

"Bug: Calling DeleteLocalRef() and continuing to use the deleted reference
It shouldn’t need to be said that it’s illegal to continue to use a reference after calling DeleteLocalRef() on it, but because it used to work, so you may have made this mistake and not realized. The usual pattern seems to be where native code has a long-running loop, and developers try to clean up every single local reference as they go to avoid hitting the local reference limit, but they accidentally also delete the reference they want to use as a return value!

The fix is trivial: don’t call DeleteLocalRef() on a reference you’re going to use (where “use” includes “return”)."

I am little confused about the inconsistency.


Solution

  • What SDK level are you targeting? If you target 13 or lower (pre ICS) then you get the old JNI behaviour and this code should work (though it's still technically incorrect)

    If you target 14 (ICS) or higher then the code shown will fail with the giveaway error:

    memory map fault addr deadd00d
    

    Note, the code will also work if you target SDK 14+, but run the app on an earlier version of Android