Search code examples
java-native-interface

ReleaseStringUTFChars with non-original jstring argument?


In order to minimize JNI marshalling, I want to store some strings on the C++ side as static variables via a setup method, use them in a different JNI method call rather than passing them each time, and then release the strings later with yet another JNI method call. For example,

C++ code:

static const char *stringValue1;

extern "C" JNIEXPORT void JNICALL
Java_mypackage_myclass_setValue1(JNIEnv* env, jclass jobj, jstring javaString) {
    jboolean isCopy;
    if(!env->IsSameObject(javaString, NULL)) {
        const char *stringValue1= env->GetStringUTFChars(javaString, &isCopy);
    }
}

extern "C" JNIEXPORT void JNICALL
Java_mypackage_myclass_execute(JNIEnv* env, jclass jobj, jint javaInt) {
    // ... use the stringValue1 static variable - otherwise, this method would need another jstring argument.
}

extern "C" JNIEXPORT void JNICALL
Java_mypackage_myclass_releaseValue1(JNIEnv* env, jclass jobj, jstring javaString) {
    if(stringValue1 != 0) {
        env->ReleaseStringUTFChars(javaString, stringValue1);
    }
}

Java code:

myclass.setValue1("hello")
for(int i = 0; i < 10; i++) {
    myclass.execute(i); // execute needs the "hello" string, but we try to store it in the C++ side rather than pass it in each loop iteration.
}
myclass.releaseValue1("hello");

Is this a valid JNI pattern? In all of the JNI examples I have seen, both calls to GetStringUTFChars and ReleaseStringUTFChars occur in the same method/scope. In this example, they do not occur in the same scope, and the jstring argument could possibly not be the same Java String either.


Solution

  • Yes, the documentation states

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

    This is corroborated by the implementation in Hotspot, which just allocates off-heap memory for a copy.