Passing pointers between C and Java through JNI - java

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

Related

Android JNI C++ Code always get "same" jobject value for 2 different SurfaceView object

In Android JAVA code:
public native int addRenderer(int channel, Object glSurface);
Context context = getApplicationContext();
SurfaceView svRemotePartyA = new SurfaceView(context);
SurfaceView svRemotePartyB = new SurfaceView(context);
addRenderer(0, svRemotePartyA);
addRenderer(1, svRemotePartyB);
In Android JNI C++ code:
extern "C" jint JNIEXPORT JNICALL Java_addRenderer(
JNIEnv* jni,
jobject j_vie,
jint channel,
jobject surface) {
LOG(LS_INFO) << "Java_addRenderer(): surface=" << surface;
// some processing
}
When I run the programme, I always read the following log! both SurfaceView object have same value in JNI C++ code log output:
(render_manager.cc:175): Java_addRenderer(): surface==0xbeed6120
(render_manager.cc:175): Java_addRenderer(): surface==0xbeed6120
What's the problem?
You look at local references, which should never be used beyond the context of the same JNI method. If you get a global reference for this jobject, you will get 2 different ones.
You should not attempt to associate a meaning with the specific bit pattern of a JNI reference.
For example, in Dalvik, local references are just indices into a table on the stack. If you make the same call several times with different objects, you will see the same "value" for the reference each time, because the object reference is sitting in the same place in the local reference table.
(It's not quite that simple -- Dalvik actually tucked a trivial serial number into the reference to make it easier to tell when a local ref was used after it had been reclaimed -- but you get the idea.)
Similarly, you cannot make the assumption about global references. If you create two global references to the same object, it's very likely that those references will have different 32-bit values.
Every VM is different. Old (pre-ICS) versions of Dalvik actually passed raw pointers around, and you could compare the reference values to determine if two objects were the same. The switch to indirect references required fixing up a few things.
If you want to tell if two objects are the same, you need to have references to both, and use the JNI IsSameObject() function.
Some additional background is here.

C Best way of modifying values in a function

I developed with Java since a few years, now I wanted to learn C and I noticed a few differences.
In Java when I want to return something from a function(e.g. read user input i would write
String s;
s = new Scanner(System.in).nextLine();
In C I would write
char s[20];
scanf("%d", name);
The difference is, in Java the function returns a value that can be assigned directly to a variable, while in C the function takes the variable name as an argument(respectivly the pointer to the variable).
I have noticed this with many C functions. When I write my own functions, should I do it like I'm used to in Java, or should I use the C style of assigning/returning values from functions?
The biggest consideration in doing things in C only with return values is lack of exceptions. Unlike Java, where error conditions can be reported outside of regular call/return process, C has no such capabilities. In other words, Scanner has an option of throwing an exception when there is no next line; scanf does not have such an option.
If you would like to return an error status from your function, you are limited to (1) returning it in a static variable (not safe for concurrency), (2) returning it as the return value, or (3) returning it in a separate "error" object. Sometimes options (2) and (3) are combined.
As the result, you will often see C APIs that can fail structured like scanf, when the status is returned as the return value, and the rest of the values are modified through pointers.
if (scanf("%d%d", &i, &j) == 2) {
... // Got 2 numbers
} else {
fprintf(stderr, "Wrong input! Expected two numbers.");
}
APIs that do not fail (say, isalpha(ch) or tolower(ch)) return their value directly.
#DasBlinkenLight has an excellent point: Sometimes you need the return value of a function to pass back an integer indicating an error occurred and what kind of error occurred.
Another reason, as #chmike points out, is that if you wanted to return a string in this case, you would have to use malloc() (C's equivalent of Java's new). But C doesn't have garbage collection, so it must be explictly freed. Because of this, it is often "bad etiquette" to pass to other exterior functions a pointer that must be freed. Who is to say that the programmer even wants memory to be allocated on the heap? Using the heap is expensive, and often the whole reason the programmer is using C is because the program in question needs to be fast.
If the programmer who calls your function wanted to use the heap, they would do so in the case of scanf by calling malloc() themselves, then giving scanf a pointer to the new memory location which you could then fill with your function. That way the caller of scanf can keep track of all the memory that was allocated, and what memory was not.
When APIs do return allocated pointers, it's usually because it can't be avoided, and they explicitly document this and usually provide a function to free the memory properly, as is the case with POSIX regex's regfree or glob's globfree. This way, if the library does allocate the memory, the library also frees it.
Whereas in Java there is such a thing called a garbage collector, in C you are responsible of the memory management.
Java is 'give it to me'.
String s = MyFunction(); // Give it to me.
In Java when you call a function that retrieve data from somewhere it just allocate it transparently and return it, the garbage collector will free it later.
C is 'put it there'.
In C you have to manage the memory. The common practice is to first make some place to put the data then try to retrieve it.
Also your code should be more something like this:
char s[80]; // Static memory allocation, we hope it is enough.
scanf("%79s", s); // Now we retrieve data. (Put it there).
Or something like this:
char* s = malloc(80 * sizeof(char)); // Dynamic memory allocation, we hope it is enough.
scanf("%79s", s); // Now we retrieve data. (Put it there).
// Do stuff with data
free(s); // Be responsible.
So, yes, you should use the C style of assigning/returning values (it make sense, after all you are doing C).
One more point, if you code it like Java here what you will have:
char* MyTest() {
char* a = "pipo";
return a; // Big fail, 'a' is local and will not exist anymore after return.
}
char* MyOtherTest() {
char a[]= "pipo";
char* b = malloc(80 * sizeof(char));
strncpy(b, a, sizeof(a));
return b; // My bet this one will never be freed.
}
That last example breaks a well know good practice rule, the caller should be responsible of allocating/freeing the memory.
The only exception I see is for value type, like simple type or struct.
// Nice and simple.
int MyAdd(int a, int b) { return a+b; }
// Why ? just Why ?
void MyAdd(int a, int b, int* r) { *r = a+b; }
Java is object oriented and returns an object which is a pointer to the object.
In C you can return a pointer as well, but not an array. The C code you show is not correct because s, declared as a pointer to a char, is not initialized. Scanf expect a pointer to a preallocated buffer as second argument. It will write the input string into the buffer. I guess you meant scanf("%d", s);.
The C code you wrote will not work because s doesn't point to an allocated buffer to store the chars. You could define s as char s[1024]; in which case s is equivalent to a pointer to a buffer of 1024 chars.
You could also define s a char *s = malloc(1024*sizeof(char)); which will dynamically allocate the buffer for s. You then need to call explicitly free(s) to release the buffer when you don't need it anymore. This is because C doesn't have a garbage collector as in Java.
well, you should know the main difference between C and Java,
Java is Object Oriented programming while C is not.
in Java almost everything is Object ( except primitives).
The way you called Scanner class is a very bad approach,
you should do it as :
Scanner scanner= new Scanner(System.in);
then call it to get string:
String s = scanner.nextLine();
The reason being is because everytime you call new Scanner(System.in) you assign your scanner to the same Object so it will start over from the start of the System.in meaning, you keep getting the same input over and over.
however in C, its not like this. since there its not an object you call.
So in short just remember in java everything is a reference (except primitive values of cource) to something else while in C its not the case
EDIT:
in terms of sending parameter to a method java can be tricky, because it depends on if you are sending a primitive data or an object.
for this reason it is normally better to get the method return something rather than sending the data that needed to be set as parameter
for example take a look at the scenario:
1. Example 1
public void addOne(int i){
i++;
}
public static void main(String... args){
int i=0;
addOne(i);
System.out.println(i);
}
output= 0;
2. Example 2
public int addOne(int i){
return i++;
}
//output = 1
public static void main(String... args){
int i=0;
i = addOne(i);
System.out.println(i);
}
To read a char array in C, you first have to inialize the actual array with a limit of how long it can be. Somthing like this:
char str[20];
scanf("%s", &str);
Note the %s format string telling scanf to capture a string, %d is for integers.

Return MPI::Request[] type from JNI and access elements of Request in Java

I'm looking to return an MPI::Request[] type from a native C++ function to Java (via JNI) and subsequently access elements in the MPI::Request[] array from the Java side.
JNIEXPORT jobjectArray JNICALL Java_mpiJNI_mpiTEST(JNIEnv *env, jobject obj) {
MPI::Request req[8];
return req; // Error: Can't convert req to jobjectArray type
}
The only return types I know of that would be close are jobjectArrays and this does not work. Java doesn't know what an MPI::Request[] type is.
I've not wanted to use things like MPJ or MPIJava because I don't know that there is much support for future MPI work in Java and want to have code that will persist through many cluster updates and configurations. If someone knows more about this matter I would be interested to hear more.
You need to return a JNI type of type jobjectArray. JNI will not convert that req pointer to a jobjectArray for you. Also note that how java lays out object arrays and
First off, you are allocating an array on the C++ stack. This is not a persistent memory and thus req pointer will be garbage when your JNI method returns. So if you want to preserve or allocate the native array storage, you will need to allocate the memory with 'new' and have a persistent pointer to your array.
What I would suggest, is that instead of returning and creating a object array, you return a single "pointer" value back to java to the begining of the the Request array, just like you would do in C++.
In order to preserve a native pointer inside a Java object, the typical trick is to convert the pointer to a java 'long' primitive type, which is long enough to hold the actual native address on most platforms. The store the return 'long' in your java class as field.
Next time you need access to the native MPI::Request array, you make a call to a native java method and pass it the address value stored as 'long' and in you corresponding JNI method, convert the JNI jlong parameter back to a pointer and typecast it to MPI::Request *req and thus you will have successfully created the request in your java/jni method, returned it, and stored inside a java class and then again used it natively in a second method where you can make the C++ calls to create/send those requests and so on.
Lastly, since you dynamically allocated the native memory for the MPI::Result[], remember to make another java native method that will again convert the long value to a pointer and release the memory with C++ delete statement, after you no longer need that array. Otherwise you will have a memory leak.
So here is how I would rewrite your JNI method:
JNIEXPORT jlong JNICALL Java_mpiJNI_mpiTEST(JNIEnv *env, jobject obj) {
MPI::Request *req = new MPI::Request[8]; // Don't forget to release memory leater
uintptr_t storage = (uintptr_t)ptr
return (jlong) storage;
}

Do C++ objects in Android JNI native code invoke garbage collection?

So, I've got a conceptual question. I've been working with JNI on Android for the purposes of doing low-level audio "stuff." I've done plenty of audio coding in C/C++, so I figured that this would not be much of a problem. I decided to do use C++ in my "native" code (because who doesn't love OOP?). The issue I've encountered seems (to me) to be a strange one: when I create an object for processing audio in the C++ code, and I never pass this object to Java (nor the other way around), calling methods on this object seems to invoke the garbage collection quite often. Since this is happening inside audio callbacks, the result is stuttering audio, and I get frequent messages along the lines of:
WAIT_FOR_CONCURRENT_GC blocked 23ms
However, when I perform the same operations by creating static functions (rather than invoking member methods on a memeber object) the performance of the app seems to be fine, and I no longer see the above log message.
Basically, is there any reason calling a static function should have better performance than calling member methods on a member object in native code? More specifically, are member objects, or limited scope variables that live entirely inside the native code of a JNI project involved in garbage collection? Is the C++ call stack involved in GC? Is there any insight anybody can give me on how C++ memory management meets Java memory management when it comes to JNI programming? That is, in the case that I'm not passing data between Java and C++, does the way I write C++ code affect Java memory management (GC or otherwise)?
Allow me to try to give an example. Bear with me, 'cause it's freaking long, and if you think you have insight you're welcome to stop reading here.
I have a couple of objects. One that is responsible for creating the audio engine, initializing output, etc. It is called HelloAudioJNI (sorry for not putting compile-able examples, but there's a lot of code).
class CHelloAudioJNI {
... omitted members ...
//member object pointers
COscillator *osc;
CWaveShaper *waveShaper;
... etc ...
public:
//some methods
void init(float fs, int bufferSize, int channels);
... blah blah blah ...
It follows that I have a couple more classes. The WaveShaper class looks like this:
class CWaveShaper : public CAudioFilter {
protected:
double *coeffs;
unsigned int order;//order
public:
CWaveShaper(const double sampleRate, const unsigned int numChannels,
double *coefficients, const unsigned int order);
double processSample(double input, unsigned int channel);
void reset();
};
Let's not worry about the CAudioFilter class for now, since this example is already quite long. The WaveShaper .cpp file looks like this:
CWaveShaper::CWaveShaper(const double sampleRate,
const unsigned int numChannels,
double *coefficients,
const unsigned int numCoeffs) :
CAudioFilter(sampleRate,numChannels), coeffs(coefficients), order(numCoeffs)
{}
double CWaveShaper::processSample(double input, unsigned int channel)
{
double output = 0;
double pow = input;
//zeroth order polynomial:
output = pow * coeffs[0];
//each additional iteration
for(int iteration = 1; iteration < order; iteration++){
pow *= input;
output += pow * coeffs[iteration];
}
return output;
}
void CWaveShaper::reset() {}
and then there's HelloAudioJNI.cpp. This is where we get into the meat of the issue. I create the member objects properly, using new inside the init function, thusly:
void CHelloAudioJNI::init(float samplerate, int bufferSize, int channels)
{
... some omitted initialization code ...
//wave shaper numero uno
double coefficients[2] = {1.0/2.0, 3.0/2.0};
waveShaper = new CWaveShaper(fs,outChannels,coefficients,2);
... some more omitted code ...
}
Ok everything seems fine so far. Then inside the audio callback we call some member methods on the member object like so:
void CHelloAudioJNI::processOutputBuffer()
{
//compute audio using COscillator object
for(int index = 0; index < outputBuffer.bufferLen; index++){
for(int channel = 0; channel < outputBuffer.numChannels; channel++){
double sample;
//synthesize
sample = osc->computeSample(channel);
//wave-shape
sample = waveShaper->processSample(sample,channel);
//convert to FXP and save to output buffer
short int outputSample = amplitude * sample * FLOAT_TO_SHORT;
outputBuffer.buffer[interleaveIndex(index,channel)] = outputSample;
}
}
}
This is what produces frequent audio interruptions and lots of messages about garbage collection. However, if I copy the CWaveShaper::processSample() function to the HelloAudioJNI.cpp immediately above the callback and call it directly instead of the member function:
sample = waveShape(sample, coeff, 2);
Then I get beautiful beautiful audio coming out of my android device and I do not get such frequent messages about garbage collection. Once again the questions are, are member objects, or limited scope variables that live entirely inside the native code of a JNI project involved in garbage collection? Is the C++ call stack involved in GC? Is there any insight anybody can give me on how C++ memory management meets Java memory management when it comes to JNI programming? That is, in the case that I'm not passing data between Java and C++, does the way I write C++ code affect Java memory management (GC or otherwise)?
There is no relationship between C++ objects and Dalvik's garbage collection. Dalvik has no interest in the contents of the native heap, other than for its own internal storage. All objects created from Java sources live on the "managed" heap, which is where garbage collection takes place.
The Dalvik GC does not examine the native stack; each thread known to the VM has a separate stack for the interpreter to use.
The only way C++ and managed objects are related is if you choose to create a relationship by pairing objects in some way (e.g. creating a new managed object from a C++ constructor, or deleting a native object from a Java finalizer).
You can use the "Allocation Tracker" feature of DDMS / ADT to see the most-recently created objects on the managed heap, and from where they are being allocated. If you run that during the GC flurry you should be able to tell what's causing it.
Also, the logcat messages show the process and thread IDs (from the command line use, adb logcat -v threadtime), which you should check to make sure that the messages are coming from your app, and also to see which thread the GC activity is occurring on. You can see the thread names in the "Threads" tab in DDMS / ADT.
CHelloAudioJNI::init(...) stores a pointer to a stack variable (double coefficients[2]) in
waveShaper. When you access waveShaper->coeffs after coefficients has gone out of scope, BadThings(tm) happens.
Make a copy of the array in your CWaveShaper constructor (and don't forget to delete it in your destructor). Or use std::array.

Safe to pass objects to C functions when working in JNI Invocation API?

I am coding up something using the JNI Invocation API. A C program starts up a JVM and makes calls into it. The JNIenv pointer is global to the C file. I have numerous C functions which need to perform the same operation on a given class of jobject. So I wrote helper functions which take a jobject and process it, returning the needed data (a C data type...for example, an int status value). Is it safe to write C helper functions and pass jobjects to them as arguments?
i.e. (a simple example - designed to illustrate the question):
int getStatusValue(jobject jStatus)
{
return (*jenv)->CallIntMethod(jenv,jStatus,statusMethod);
}
int function1()
{
int status;
jobject aObj = (*jenv)->NewObject
(jenv,
aDefinedClass,
aDefinedCtor);
jobject j = (*jenv)->CallObjectMethod
(jenv,
aObj,
aDefinedObjGetMethod)
status = getStatusValue(j);
(*jenv)->DeleteLocalRef(jenv,aObj);
(*jenv)->DeleteLocalRef(jenv,j);
return status;
}
Thanks.
I'm not acquainted with the details of JNI, but once thing I noticed is this:
return (*jenv)->CallIntMethod(jenv,jStatus,statusMethod);
That looks like the official JNI code and it is taking a jobect as a parameter. If it works for JNI, there is no reason it can't work for your code.
All jni objects are valid until the native method returns. As long as you dont store non global jni objects between two jni calls everything should work.
The invocation of a jni function should work like this:
Java function call
create native local references
call native function
do your stuff
exit native function
release existing local references
return to java
The step 4 can contain any code, local references stay valid until step 6 if not release before.
If you want to store jni objects on the c side between two calls to a native java function you have to create global references and release them later. Not releasing a global reference leads to memory leaks as the garbage collector is unable to free the related java objects.

Categories

Resources