Efficiently send large int[] over sockets in Java Efficiently send large int[] over sockets in Java android android

Efficiently send large int[] over sockets in Java


As I noted in a comment, I think you're banging against the limits of your processor. As this might be helpful to others, I'll break it down. Here's your loop to convert integers to bytes:

    for(int i = 0; i < input.length; i++) {        output[i*4] = (byte)(input[i] & 0xFF);        output[i*4 + 1] = (byte)((input[i] & 0xFF00) >>> 8);        output[i*4 + 2] = (byte)((input[i] & 0xFF0000) >>> 16);        output[i*4 + 3] = (byte)((input[i] & 0xFF000000) >>> 24);    }

This loop executes 500,000 times. You 600Mhz processor can process roughly 600,000,000 operations per second. So each iteration of the loop will consume roughly 1/1200 of a second for every operation.

Again, using very rough numbers (I don't know the ARM instruction set, so there may be more or less per action), here's an operation count:

  • Test/branch: 5 (retrieve counter, retrieve array length, compare, branch, increment counter)
  • Mask and shift: 10 x 4 (retrieve counter, retrieve input array base, add, retrieve mask, and, shift, multiply counter, add offset, add to output base, store)

OK, so in rough numbers, this loop takes at best 55/1200 of a second, or 0.04 seconds. However, you're not dealing with best case scenario. For one thing, with an array this large you're not going to benefit from a processor cache, so you'll introduce wait states into every array store and load.

Plus, the basic operations that I described may or may not translate directly into machine code. If not (and I suspect not), the loop will cost more than I've described.

Finally, if you're really unlucky, the JVM hasn't JIT-ed your code, so for some portion (or all) of the loop it's interpreting bytecode rather than executing native instructions. I don't know enough about Dalvik to comment on that.


Java was IMO never intended to be able efficiently reinterpret a memory region from int[] to byte[] like you could do in C. It doesn't even have such a memory address model.

You either need to go native to send the data or you can try to find some micro optimizations. But I doubt you will gain a lot.

E.g. this could be slightly faster than your version (if it works at all)

public static byte[] intToByte(int[] input){    byte[] output = new byte[input.length*4];    for(int i = 0; i < input.length; i++) {        int position = i << 2;        output[position | 0] = (byte)((input[i] >>  0) & 0xFF);        output[position | 1] = (byte)((input[i] >>  8) & 0xFF);        output[position | 2] = (byte)((input[i] >> 16) & 0xFF);        output[position | 3] = (byte)((input[i] >> 24) & 0xFF);    }    return output;}


I would do it like this:

Socket senderSocket = new Socket(address, 4446);OutputStream os = senderSocket.getOutputStream();BufferedOutputStream bos = new BufferedOutputStream(os);DataOutputStream dos = new DataOutputStream(bos);dos.writeInt(array.length);for(int i : array) dos.writeInt(i);dos.close();

On the other side, read it like:

Socket recieverSocket = ...;InputStream is = recieverSocket.getInputStream();BufferedInputStream bis = new BufferedInputStream(is);DataInputStream dis = new DataInputStream(bis);int length = dis.readInt();int[] array = new int[length];for(int i = 0; i < length; i++) array[i] = dis.readInt();dis.close();