views:

1546

answers:

4

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 :)

+1  A: 

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 long 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.

Gunslinger47
About your second paragraph: The only thing to look out for is to make sure that any memory allocated gets deallocated as well. The recommended approach is to have some kind of close/dispose() method on the object holding the reference. finalizers are tempting but they come with a couple of drawbacks making it worth avoiding them if possible.
Fredrik
I shouldn't have written "the only thing" btw... JNI is full of pits to fall into.
Fredrik
I already included functions to free allocated memory, so that should no problem :) The main problem still is: Does memory stay allocated if i do net free it? I mean, including addresses and values...i know that i will get memory leaks an so on if i don't do it, so i already included that ;-)
Volker
@Volker: It depends on how you allocate it. The only exception to the rule that you have to deallocate/free the memory yourself is normally if something is allocated on the stack. If it is, it will be "freed" when the stack pointer is moved back at exit of a function. So if you have allocated memory using some kind of memory allocation function (except for "alloca") you will have to free it. It is really not at all related to java. As soon as you have made the JNI jump the rules are from the C world unless you use java objects.
Fredrik
Fredrik, your answer is correct, and really ought to be moved into its own answer for credit.
Jonathan Feinberg
+1  A: 

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.

Marc Paradise
+2  A: 

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.

tulskiy
That's how i did it now - i send the pointer back to java as a long and pass it to C. But how do i tell C that the long it just received is an address?long *ptr = (long*)That's what i tried, but i don't get the value which should be at the address, i only get the address itself (or some other addresses but no value :( )
Volker
...there should be asterisks before ptr and after the second long...
Volker
`MyClass *pObject = ...; long lp = (long)pObject; pObject = (*pObject)lp;`
Gunslinger47
A: 

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 = (*pObject)lp;
    ...
}
Dan Berindei