I need to send an array of 500,000 ints over a socket between two Android devices. Currently, I'm spending a lot of time converting the int[] to a byte[] so that Java's socket will accept it (see my previous question Efficiently send large int[] over sockets in Java, where we determined there's no faster way to do the typecasting in Java).
My question now is, if I take the int[] and pass it through JNI to the Android NDK, can I expect the typecasting to byte[] to go any faster in native code? I know typecasting int* to char* is quite simple in plain-old C, however I'm wondering if the JNI will negate any performance gains.
Furthermore, once I have a byte[] in my native code, can I efficiently pass it back to my Java code or do I need to implement the socket in C as well?
Edit 1: People have been posting a lot of answers without clicking on the link. Using ByteBuffers is not a good option, its actually way slower than mask-and-shift, which is still way slower than my performance critical code needs! That's why I'm asking about the NDK.
Edit 2: I changed the text above to say that C code can cast from int* to char* instead of int[] to byte[]. Hopefully that clarifies the question.
Edit 3: To clarify my use-case, this is a research problem where I distribute a large array of ints across multiple devices and sort the list in parallel. Assume that I have 500,000 ints in Java (doesn't matter where they come from) and I need to get them off the device via a socket as quickly as possible. Answers that say "don't start with an array of ints" aren't helpful. Additionally, my application code needs to be as close to 100% Java as possible. If native typecasting and sockets improve performance, that's ok, but I can't do anything else (i.e. the sort) natively.
No, using JNI/NDK won't give you a performance boost. First of all when you try to get the array over to the native code you'll have to copy it or use a directly allocated ByteBuffer. Turns out the implementation of Dalvik VM always returns direct pointer from Get*ArrayElements(). I do doubt that you'll get a performance bump because calls through JNI have overhead cost. Finally C++ and Java have the very close performance in this scenario (see C++ performance vs. Java/C#).
Take a look at this question and the first answer for a fast way to convert the int[] to a byte[] from Java How to convert int[] to byte[]
Is there a reason you're using an int[] instead of byte[] to begin with? If it's an image we might be able to recommend ways of avoiding conversion.
Use a SocketChannel
and you can use ByteBuffer
s instead.
buffer.asIntBuffer().put(ints);
do {
channel.write(buffer);
} while (buffer.hasRemaining());
If the Java code needs efficient access to int[]
, then there is a good chance that native send/receive with sockets is worth the effort.
But often it is OK to use IntBuffer instead of int[]. In this case, you can allocate a ByteBuffer and get an IntBuffer from it:
ByteBuffer bb = ByteBuffer.allocate(500000*4);
IntBuffer ib = bb.asIntBuffer();
You should experiment with both allocate() and allocateDirect(), see " ByteBuffer.allocate() vs. ByteBuffer.allocateDirect() " and http://objectissues.blogspot.co.il/2005/10/java-nio-allocate-vs-allocatedirect.html.
Important! In this case, you will get UnsupportedOperationException
if you try to use ib.array()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With