How to release jstring in a loop correctly?

Since your loop is creating the local ref (GetObjectField), you need to release it (DeleteLocalRef) in the loop, or you'll run up against the limit on local references. You'll have to completely process the Java string between to two calls.

Since you want to keep the bytes of the string for use outside of the loop, you need to copy the bytes because the JVM's pinning (or temporary copy)(GetStringUTFChars) has to be released (ReleaseStringUTFChars) before the string reference is released.

So the sequence for the string inside the loop must be:

  1. GetObjectField
  2. GetStringUTFChars
  3. make your own copy
  4. ReleaseStringUTFChars
  5. DeleteLocalRef

Note: With GetStringUTFChars you are getting a pointer to a modified UTF-8 encoding of the Java String. Two points here:

  1. Your code should be able to handle modified UTF-8 encoded characters. (It has between one and six bytes per character and encodes NUL in a peculiar way.)
  2. The documentation doesn't say if the array is 0-terminated. You can use GetStringUTFLength to get the number of bytes in the modified UTF-8 encoding—not counting any 0-terminator. (Various JNI implementations and The Book do agree that the array is 0-terminated.) If you want to make your own copy with a terminator, be sure to add room for the terminator.

If you'd rather use a UTF-16 encoding, use GetStringChars and GetStringLength. In this case, the array is definitely not terminated; It uses the internal count and string bytes without any conversion.

Or, if you want to change character sets, to say, real "UTF-8", "ASCII", "CP437" or "Windows-1252" or something else your code can handle, use a String.getBytes overload or the Charset class. Use the Charset class if you want control over how to handle characters that are not supported in the target character set.