5

What is the fastest way to fill up a pre-allocated ByteBuffer in Java?

I first set the size of the byte buffer with allocateDirect(), this only needs to be done once. After, I need to fill it up continuously (recycling it) as fast as possible with new data which arrives as a byte[] array, around every 5ms, and without eating memory as I have already pre-allocated the byte buffer. At the moment, I use the put() instruction, which in my system takes around 100ms to complete. Is there another way to fill up the byte buffer? Does thewrap() function run faster without re-allocating the array?

0xCursor
  • 2,242
  • 4
  • 15
  • 33
PerracoLabs
  • 16,449
  • 15
  • 74
  • 127
  • You can try System.arraycopy. Check: [Is it better to use System.arraycopy(…) than a for loop for copying arrays?](http://stackoverflow.com/questions/18638743/is-it-better-to-use-system-arraycopy-than-a-for-loop-for-copying-arrays) – user3668129 Jan 09 '16 at 18:11

2 Answers2

8

I would hope you mean byte[] not Byte[]

A put() is the fastest way to copy a byte[] into a ByteBuffer. An even faster way is to write into the ByteBuffer in the first place and not use a byte[] at all.

If the copy is taking 100ms, perhaps you are copying too much data. In this test it copies 1 MB in 128 micro-seconds.

ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024);
byte[] bytes = new byte[bb.capacity()];

int runs = 50000;
long start = System.nanoTime();
for (int i = 0; i < runs; i++) {
    bb.clear();
    bb.put(bytes);
}
long time = System.nanoTime() - start;
System.out.printf("Average time to copy 1 MB was %.1f us%n", time / runs / 1e3);

prints

Average time to copy 1 MB was 128.9 us
giampaolo
  • 6,906
  • 5
  • 45
  • 73
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Oops, yes I meant byte[]. So the only way to fill up continuously the ByteBuffer, the fastest way possible, is by using ".put(...)"? The data I must fill up in every cycle, is as in your test, around 1MB, which I cannot get around or reduce. – PerracoLabs Jun 19 '12 at 08:50
  • Are you sure its 100 ms and not 100 micro-seconds? If you cannot reduce it the best solution is to not use a byte[] at all and have what ever produces this write directly to the ByteBuffer. – Peter Lawrey Jun 19 '12 at 09:01
  • yes it takes around 100ms. Unfortunately the data I get from the hardware callback arrives as a byte[] array, and the final instruction that needs to process it, only accepts a ByteBuffer, which also I can't change. So I must find the fastest possible way to copy this data across, and without re-allocating memory all the time. – PerracoLabs Jun 19 '12 at 09:30
  • Can you run my test because there is no way that a put() on 1 MB should be taking 100 ms? It should be closer to 0.1 ms. – Peter Lawrey Jun 19 '12 at 09:34
  • 2
    The answer is good and I like that you provide a testcode for the speed of ByteBuffer.put() .... But actually it does not provide any information on the speed of `ByteBuffer.wrap()`... You say `put()` is the fastest way, but actually you need to take into account the creation of the ByteBuffer object also... `ByteBuffer.wrap()` copies the bytes and instantiates a ByteBuffer at the same time.. Are you sure this is slower than instantiating a ByteBuffer and then using `put()` to copy the bytes? Or do you normally just use one ByteBuffer Object for several byte copy tasks? – Jan Dec 14 '15 at 12:13
  • @Jan You are right that creating a ByteBuffer each time is expensive, which is why I assumed you would pool or reuse this ByteBuffer as most packages do e.g. in a ThreadLocal. `wrap` couldn't copy any bytes and if you alter the ByteBuffer, this alters the byte[]. The ByteBuffer.wrap cannot be reused for different byte[] (without using reflection) – Peter Lawrey Dec 14 '15 at 17:00
2

wrap should be much faster, as --if I understand the doc correctly-- it does not copy the byte array, but just sets the member variables (capacity/limit/position). wrap only makes sense, if you already got the byte[] with the desired data from somewhere, of course.

datafiddler
  • 1,755
  • 3
  • 17
  • 30