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.
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
Related
My function looks like below. And it is getting executed for a number of times.At certain point it is crashing at jobject nvarObject = env->GetObjectField (var1, nvar1) giving error JNI error : Local reference table overflow 512 entries.
Could anyone look into this issue and throw some light.
All JNI methods that return a jobject or similar object reference are creating local references in the reference table. These references get automatically cleaned up when you return control to the JVM, but if you are creating many references (for instance, in a loop), you'll need to clean up them up manually.
You're on the right track by calling DeleteLocalRef on the cls reference, but notice that GetObjectField also returns a jobject, so the reference returned there should be deleted before exiting the function, as well.
Also make sure to clean up any existing references before returning from error conditions!
Another way to do this: at the top of the function that you're calling in a loop, call PushLocalFrame( env, 5 ) and call PopLocalFrame(env) before any place in the function where you return. This will automatically clean up any references created during that function call. The second argument is the number of local references you want in the frame -- if you need more than 5 local references during the execution of the function, use a value higher than 5.
Say I have the following Java code:
public class Test {
public static int foo() {
throw new RuntimeException();
}
}
which loads a native library in the usual manner. The native library registers and caches the JVM or whatever, and then, later on, this function gets executed:
JNIEnv* sEnv; // initialised somewhere properly
void throwMeARiver() {
jclass c = sEnv->FindClass("Test");
jmethodID m = sEnv->GetStaticMethodID(c, "foo", "()I");
jint i = sEnv->CallStaticIntMethod(c, m);
printf("Got %d\n", (int)i);
}
Evidently sEnv->CheckException() will now return JNI_TRUE, but what will the native function print out? In Java, throwing an Exception makes the JVM stop executing the method it's in until it finds an appropriate handler, so foo()'s return value is undefined. So is i also undefined?
I can't find any specs or anything saying otherwise, so presumably i /is/ undefined. There's no 'normal' range of CallStaticIntMethod in this case, unlike most JNI functions.
I'm trying this now, but I'm mainly asking this to see if there's a mandated behaviour somewhere.
While the variable i will be defined, its value is undetermined. In this situation, most likely, the value will be 0, but only if the JVM initialized the value in its implementation. Otherwise, it will be equal to whatever the data is present at its location in memory.
Its up to the implementer of the native function to properly check for an exception following a CallXXXMethod() via env->CheckException(), env->ExceptionOccurred(), and env->ExceptionDescribe(). Finally, a call to env->ClearException() to remove the exception.
No, JNI CheckException() is not equivalent to Java try … catch, therefore your new RuntimeException() will propagate further and maybe not get caught at all.
Thanks to #EJP for correcting me: actually, any Throwable from Java is intercepted by the C/C++ caller. From my tests on Android, the value returned is whatever happens to be in some unpredictable memory location (stack?).
For more discussion of JNI and exceptions, see How to catch JNI/Java Exception.
I'm returning a jstring from a JNI method. I delete the local reference to it before returning the value.
JNIEXPORT jstring JNICALL TestJNIMethod( JNIEnv* env, jclass )
{
jstring test_string = env->NewStringUTF( "test_string_value" );
env->DeleteLocalRef( test_string );
return test_string;
}
Would the calling JAVA method be still able to access the returned jstring or would the Garbage collector cleanup the memory?
No it will not, however your code will work on Android versions earlier than ICS. From ICS on this code will correctly fail.
In general you don't need to delete local references yourself, once the JNI function returns to Java the references will get GC'd.
The exception to that rule is if you create a lot of them, perhaps in a loop. Then it is possible to fill the local reference table. See IBM: Overview of JNI object references.
You should read JNI Local Reference Changes in ICS. Even if you are not writing for Android, it still identifies many common mistakes.
At the moment, i'm trying to create a Java-application which uses CUDA-functionality. The connection between CUDA and Java works fine, but i've got another problem and wanted to ask, if my thoughts about it are correct.
When i call a native function from Java, i pass some data to it, the functions calculates something and returns a result. Is it possible, to let the first function return a reference (pointer) to this result which i can pass to JNI and call another function that does further calculations with the result?
My idea was to reduce the overhead that comes from copying data to and from the GPU by leaving the data in the GPU memory and just passing a reference to it so other functions can use it.
After trying some time, i thought for myself, this shouldn't be possible, because pointers get deleted after the application ends (in this case, when the C-function terminates). Is this correct? Or am i just to bad in C to see the solution?
Edit:
Well, to expand the question a little bit (or make it more clearly): Is memory allocated by JNI native functions deallocated when the function ends? Or may i still access it until either the JNI application ends or when i free it manually?
Thanks for your input :)
I used the following approach:
in your JNI code, create a struct that would hold references to objects you need. When you first create this struct, return its pointer to java as a long. Then, from java you just call any method with this long as a parameter, and in C cast it to a pointer to your struct.
The structure will be in the heap, so it will not be cleared between different JNI calls.
EDIT: I don't think you can use long ptr = (long)&address; since address is a static variable. Use it the way Gunslinger47 suggested, i.e. create new instance of class or a struct (using new or malloc) and pass its pointer.
In C++ you can use any mechanism you want to allocate/free memory: the stack, malloc/free, new/delete or any other custom implementation. The only requirement is that if you allocated a block of memory with one mechanism, you have to free it with the same mechanism, so you can't call free on a stack variable and you can't call delete on malloced memory.
JNI has its own mechanisms for allocating/freeing JVM memory:
NewObject/DeleteLocalRef
NewGlobalRef/DeleteGlobalRef
NewWeakGlobalRef/DeleteWeakGlobalRef
These follow the same rule, the only catch is that local refs can be deleted "en masse" either explicitly, with PopLocalFrame, or implicitly, when the native method exits.
JNI doesn't know how you allocated your memory, so it can't free it when your function exits. Stack variables will obviously be destroyed because you're still writing C++, but your GPU memory will remain valid.
The only problem then is how to access the memory on subsequent invocations, and then you can use Gunslinger47's suggestion:
JNIEXPORT jlong JNICALL Java_MyJavaClass_Function1() {
MyClass* pObject = new MyClass(...);
return (long)pObject;
}
JNIEXPORT void JNICALL Java_MyJavaClass_Function2(jlong lp) {
MyClass* pObject = (MyClass*)lp;
...
}
While the accepted answer from #denis-tulskiy does make sense, I've personnally followed suggestions from here.
So instead of using a pseudo-pointer type such as jlong (or jint if you want to save some space on 32bits arch), use instead a ByteBuffer. For example:
MyNativeStruct* data; // Initialized elsewhere.
jobject bb = (*env)->NewDirectByteBuffer(env, (void*) data, sizeof(MyNativeStruct));
which you can later re-use with:
jobject bb; // Initialized elsewhere.
MyNativeStruct* data = (MyNativeStruct*) (*env)->GetDirectBufferAddress(env, bb);
For very simple cases, this solution is very easy to use. Suppose you have:
struct {
int exampleInt;
short exampleShort;
} MyNativeStruct;
On the Java side, you simply need to do:
public int getExampleInt() {
return bb.getInt(0);
}
public short getExampleShort() {
return bb.getShort(4);
}
Which saves you from writing lots of boilerplate code ! One should however pay attention to byte ordering as explained here.
Java wouldn't know what to do with a pointer, but it should be able to store a pointer from a native function's return value then hand it off to another native function for it to deal with. C pointers are nothing more than numeric values at the core.
Another contibutor would have to tell you whether or not the pointed to graphics memory would be cleared between JNI invocations and if there would be any work-arounds.
I know this question was already officially answered, but I'd like to add my solution:
Instead of trying to pass a pointer, put the pointer in a Java array (at index 0) and pass that to JNI. JNI code can get and set the array element using GetIntArrayRegion/SetIntArrayRegion.
In my code, I need the native layer to manage a file descriptor (an open socket). The Java class holds a int[1] array and passes it to the native function. The native function can do whatever with it (get/set) and put back the result in the array.
If you are allocating memory dynamically (on the heap) inside of the native function, it is not deleted. In other words, you are able to retain state between different calls into native functions, using pointers, static vars, etc.
Think of it a different way: what could you do safely keep in an function call, called from another C++ program? The same things apply here. When a function is exited, anything on the stack for that function call is destroyed; but anything on the heap is retained unless you explicitly delete it.
Short answer: as long as you don't deallocate the result you're returning to the calling function, it will remain valid for re-entrance later. Just make sure to clean it up when you're done.
Its best to do this exactly how Unsafe.allocateMemory does.
Create your object then type it to (uintptr_t) which is a 32/64 bit unsigned integer.
return (uintptr_t) malloc(50);
void * f = (uintptr_t) jlong;
This is the only correct way to do it.
Here is the sanity checking Unsafe.allocateMemory does.
inline jlong addr_to_java(void* p) {
assert(p == (void*)(uintptr_t)p, "must not be odd high bits");
return (uintptr_t)p;
}
UNSAFE_ENTRY(jlong, Unsafe_AllocateMemory(JNIEnv *env, jobject unsafe, jlong size))
UnsafeWrapper("Unsafe_AllocateMemory");
size_t sz = (size_t)size;
if (sz != (julong)size || size < 0) {
THROW_0(vmSymbols::java_lang_IllegalArgumentException());
}
if (sz == 0) {
return 0;
}
sz = round_to(sz, HeapWordSize);
void* x = os::malloc(sz, mtInternal);
if (x == NULL) {
THROW_0(vmSymbols::java_lang_OutOfMemoryError());
}
//Copy::fill_to_words((HeapWord*)x, sz / HeapWordSize);
return addr_to_java(x);
UNSAFE_END
I have some native code which returns a jbyteArray (so byte[] on the Java side) and I want to return null. However, I run into problems if I simply return 0 in place of the jbyteArray.
Some more information:
The main logic is in Java, the native method is used to encode some data into a byte stream. don;t ask.. it has to be done like this. Recently, the native code had to be changed a bit and now it runs horribly horrible slow. After some experimentation, which included commenting out all code in the native method before the return, it turns out that returning 0 causes the slowdown. When returning an actual jbyteArray, everything is fine.
Method signatures for my code:
On the C++ side:
extern "C" JNIEXPORT jbyteArray JNICALL Java_com_xxx_recode (JNIEnv* env, jclass java_this, jbyteArray origBytes, jobject message)
On the Java side:
private static native byte[] recode(byte[] origBytes, Message message);
The native code looks something like this:
jbyteArray javaArray;
if (error != ERROR) {
// convert to jbyteArray
javaArray = env->NewByteArray((jsize) message.size);
env->SetByteArrayRegion(java_array, 0, message.size, reinterpret_cast<jbyte*>(message.buffer()));
if (env->ExceptionOccurred()) {
env->ExceptionDescribe();
error = ERROR;
}
}
if (error == ERROR) {
return 0; // Does NOT work - doesn't crash, just slows everything down horrible.
}
else {
return javaArray; // Works perfectly.
}
Does anyone know of any reasons that this could happen? Is it valid to return NULL from a native method in place of a jbyteArray, or is there another procedure to return null back to Java. Unfortunately, I had no luck on Google.
Thanks!
EDIT: Added additional information.
This is an old question but I had it too a minute ago...
You say in your question:
return 0; // Does NOT work - doesn't crash, just slows everything down horrible.
I just gave a try actually, with a jintArray as this is what my code has to allocate and return, unless an error happens (defined by some criteria not related to this topic) in which case it has to return a null result.
It happens that returning NULL (defined as ((void*)0)) works perfectly and is interpreted as null when back to the Java side. I didn't notice any degradation of the performances. And unless I missed anything returning 0 with no void * cast would not change anything to this.
So I don't think this was the cause of the slowdown you encountered. NULL looks just fine to return null.
EDIT:
I do confirm, the return value has nothing to do with performances. I just tested a same code returning a null value on a side, and its counterpart returning an object (a jintArray) on the other. Performances are similar for NULL, a jintArray of size 0, and a random jintArray of a few KBs allocated statically.
I also tried changing the value of a caller class's field, and returing void, with roughly the same performances. A very very little bit slower, probably due to the reflection code needed to catch that field and set it.
All these tests were made under Android, not under Java standalones - maybe this is why? (see comments):
An API 17 x86 emulator running under HAXM
An API 19 one, running under the same conditions
Two API 19 physical devices - an Asus tablet and a Galaxy 5 - running under Dalvik.
There's some asymmetry in your code that struck my eye: you never decide upon the type of object to return, except when returning 'nothing'. Apparently the env object decides how to allocate a javaSrray, so why not ask it to return some kind of empty array? It may be possible that the 0 that you return needs to be handled in a special way while marshaling between jni and java.
Have you tried returning a NULL reference?
This is untested (don't have a JNI development environment at hand at the moment) but you should be able to create a new global reference to NULL and return it like this:
return (*env)->NewGlobalRef(env, NULL);
EDIT That being said, you check if an exception occurs, but do not clear it. That, as far as I can understand, means that it is still "thrown" in the Java layer, so you should be able to use just that as an error indicator; then it does not matter what the function returns. In fact, calling a JNI function other than ExceptionClear()/ExceptionDescribe() when an exception is thrown is not "safe" according to the documentation. That the functions is "slow" might be caused by the ExceptionDescribe() function writing debugging information.
So, if I understand this correctly, this should be a well-behaved function throwing an exception the first time an error occurs, and returning NULL on each subsequent call (until 'error' is cleared):
if (error != ERROR) {
jbyteArray javaArray = env->NewByteArray((jsize) message.size);
env->SetByteArrayRegion(javaArray, 0, message.size, reinterpret_cast<jbyte*>(message.buffer()));
if (env->ExceptionOccurred()) {
error = ERROR;
return 0;
}
return javaArray;
} else {
return env->NewGlobalRef(NULL);
}
Again, this is untested since I dont have a JNI environment available right now.