Suppose that I have a C data-structure containing many data fields (>15):
struct MyData
{
int x;
float y;
...
}
In Java, I can store a pointer to a MyData as a long, and access members of the C data structure through JNI calls:
long mydata_p = MyDataJNI.alloc();
int x = MyDataJNI.getX( mydata_p );
float y = MyDataJNI.getY( mydata_p );
...
However, the calls to these functions are shockingly expensive (10x-100x the cost of an equivalent C function call). This is true even if the implementation getX, getY, ... is as simple as:
return ((MyData*)())->x
Q1: Why are JNI calls so expensive? What else is going on other than a call to a function pointer? (For reference, I'm looking at JNI calls in Android.)
Q2: What is the fastest what to make all of the elements of my C structure available at the Java layer?
You want to move all of the data with a single JNI call. You can either copy it into a primitive byte array (and then extract Java primitives from that using some combination of ByteArrayOutputStream and DataOutputStream), or use a direct NIO ByteBuffer (ByteBuffer.allocateDirect), which makes more sense if you need to move data back and forth. The direct ByteBuffer is specifically designed and optimized for sharing memory between the VM and native code.
Instead of storing the results of the native call in an externally managed pointer, you could have it return the result in a Java object.
The easiest would be to memcpy the C structs straight into a byte[], and then on the Java side, wrap that array in a ByteBuffer and read it with getInt(), getFloat(), etc.
You could also return an array of Java objects constructed to reflect your structs, but the code would be an unbelievable mess, somewhat akin to constructing everything through reflection with explicit memory management.
Related
I am learning about JNI nowadays. Let us say I have a C/C++ library function, which takes int* array as an input (We assume int is of 4 bytes and signed just like as it is in Java), that is, an array passed as a pointer. Would it be possible to pass a Java array of int to such function through JNI, without doing any copying (Obviously we remove the length part of the Java array while doing so)? Is the direct ByteBuffer the only viable method for doing such things?
A direct ByteBuffer would be one way of avoiding copying, as you mention yourself.
If you pass a Java array you will need to call Get<Primitive>ArrayElements, which may or may not copy (or Get<Primitive>ArrayRegion, but that would make no sense since it always copies).
There's also GetPrimitiveArrayCritical which you can use if you only need access to the elements for a "short" amount of time, and don't need to perform any other JNI calls before releasing the elements. It is "more likely" than Get<Primitive>ArrayElements to not copy.
An example:
jint len = env->GetArrayLength(myIntArray);
jint *elements = env->GetPrimitiveArrayCritical(myIntArray, NULL);
// Use elements...
env->ReleasePrimitiveArrayCritical(myIntArray, elements, 0);
See Oracle's JNI documentation.
In C/C++, you can do the following:
struct DataStructure
{
char member1;
char member2;
};
DataStructure ds;
char bytes[] = {0xFF, 0xFE};
memcpy(&ds, bytes, sizeof(ds));
and you would essentially get the following:
ds.member1 = 0xFF;
ds.member2 = 0xFE;
What is the Java equivalent?
What is the Java equivalent?
There is no Java equivalent.
Java does not allow you to create or modify objects by accessing them at that level. You should be using new or setter methods, depending on what you are trying to achieve.
(There are a couple of ways to do this kind of thing, but they are unsafe, non-portable and "not Java" ... and they are not warranted in this situation.)
The memcpy you wrote depends on the internal implementation of the struct and would not necessarily work. In java, you need to define a constructor that accepts a byte array and set the fields. No shortcuts like this, as the memory structure of the class is not defined.
In Java you cannot work with the memory directly (no memcpy) it is the advantage (disadvantage?) of Java. There are some java library methods to copy arrays: System.arraycopy().
In general, to copy some object you need to ship it with clone method.
You might be able to do that in C. But you'd be wandering into aliasing problems and a hunka hunka burning undefined behavior.
And because struct padding is up to a compiler, what you might get with your memcpy is just ds.member1 = 0xFF, ds.member2 = whatever junk happened to be on the stack at the time, because member1 was padded to occupy 4 bytes rather than just 1. Or maybe you get junk for both, because you set the top 2 bytes of a 4-byte and they're in the bottom 2 bytes.
What you're wandering into is compiler/runtime-specific memory layouts. The same is true in Java. Java itself won't let you do something so horrendously un-Java, but if you write your own JVM or debug an existing JVM written in C or C++, you could do something like that. And who knows what would happen; I'm not Java god enough to know exactly how much the JVM spec pins down JVM implementation, but my guess is, not to the degree necessary to enable interoperability of the in-memory, runtime representations of objects.
So you get undefined behavior in every language flavor. Tastes just as good in each language, too - like mystery meat.
Using the common example of a Point (x, y) object, is there a way to have it as a struct in Java 1.4? The advantage would be that there would not be a separate memory allocation for the Point object because the struct would be part of the containing object. But it would still have member functions to access it.
I'm 98% certain the answer is no but hope springs eternal...
what/why:
In our code we have 100,000+ objects (about 12 - 14% of the total memory footprint) that is an int and a boolean. If that was a C# struct inside the object, it would reduce the number of objects. And... we are looking at making it just an int where 0x40000000 is the boolean value. But handling that is a lot easier if we have member methods for that int and it's treated as a struct.
There is no struct equivalent on Java now, although I believe that they have been hinted for future versions. Still have a look at the flyweight pattern, might be what you are looking for http://en.wikipedia.org/wiki/Flyweight_pattern
No, you have to use Objects for general "structs".
However for simple data structures like pairs of ints, you can use a bit of trickery in order to save memory and increase speed.
int a = 9;
int b = 10;
long pair = (a << 32)|b;
This packs the 32 bits of a and b into a long. Here's how you extract them:
a = (int)(pair >> 32);
b = (int)pair;
An addition to tskuzzy's answer: another possibility would be to lift the int x and int y fields from the Point class into any classes that need to store point values.
Edit in response to comments:
One thing you could do is to have each class that needs to store a single point value extend a Point class. There would be no logical is-a relationship, but it gives you access to Point objects through a single interface. This wouldn't work (I don't think) for any classes that need to store multiple point values, though.
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
What is the 'correct' way to store a native pointer inside a Java object?
I could treat the pointer as a Java int, if I happen to know that native pointers are <= 32 bits in size, or a Java long if I happen to know that native pointers are <= 64 bits in size. But is there a better or cleaner way to do this?
Edit: Returning a native pointer from a JNI function is exactly what I don't want to do. I would rather return a Java object that represents the native resource. However, the Java object that I return must presumably have a field containing a pointer, which brings me back to the original question.
Or, alternatively, is there some better way for a JNI function to return a reference to a native resource?
IIRC, both java.util.zip and java.nio just use long.
java.nio.DirectByteBuffer does what you want.
Internally it uses a private long address to store pointer value. Dah !
Use JNI function env->NewDirectByteBuffer((void*) data, sizeof(MyNativeStruct)) to create a DirectByteBuffer on C/C++ side and return it to Java side as a ByteBuffer. Note: It's your job to free this data at native side! It miss the automatic Cleaner available on standard DirectBuffer.
At Java side, you can create a DirectByteBuffer this way :
ByteBuffer directBuff = ByteBuffer.allocateDirect(sizeInBytes);
Think it as sort of C's malloc(sizeInBytes). Note: It has as automatic Cleaner, which deallocates the memory previously requested.
But there are some points to consider about using DirectByteBuffer:
It can be Garbage Collected (GC) if you miss your direct ByteBuffer reference.
You can read/write values to pointed structure, but beware with both offset and data size. Compiler may add extra spaces for padding and break your assumed internal offsets in structure. Structure with pointers (stride is 4 or 8 bytes ?) also puzzle your data.
Direct ByteBuffers are very easy to pass as a parameter for native methods, as well to get it back as return.
You must cast to correct pointer type at JNI side. Default type returned by env->GetDirectBufferAddress(buffer) is void*.
You are unable to change pointer value once created.
Its your job to free memory previously allocated for buffers at native side. That ones you used with env->NewDirectByteBuffer().
There is no good way. In SWT, this code is used:
int /*long*/ hModule = OS.GetLibraryHandle ();
and there is a tool which converts the code between 32bit and 64bit by moving the comment. Ugly but it works. Things would have been much easier if Sun had added an object "NativePointer" or something like that but they didn't.
A better way might by to store it in a byte array, since native pointers aren't very Java-ish in the first place. ints and longs are better reserved for storing numeric values.
I assume that this is a pointer returned from some JNI code and my advice would be just dont do it :)
Ideally the JNI code should pass you back some sort of logical reference to the resource and not an actual pointer ?
As to your question there is nothing that comes to mind about a cleaner way to store the pointer - if you know what you have then use either the int or long or byte[] as required.
You could look to the way C# handles this with the IntPtr type. By creating your own type for holding pointers, the same type can be used as a 32-bit or 64-bit depending on the system you're on.