views:

516

answers:

5
+2  Q: 

Growing ByteBuffer

Has anyone has ever seen an implementation of java.nio.ByteBuffer that will grow dynamically if a putX() call overruns the capacity?

The reason I want to do it this way is twofold:

1) I don't know how much space I need ahead of time. 2) I'd rather not do a new ByteBuffer.allocate() then a bulk put() every time I run out of space.

I could try writing one myself, but don't want to reinvent the wheel if one of these already exists somewhere.

Any suggestions?

+5  A: 

In order for asynchronous I/O to work, you must have continuous memory. In C you can attempt to re-alloc an array, but in Java you must allocate new memory. You could write to a ByteArrayOutputStream, and then convert it to a ByteBuffer at the time you are ready to send it. The downside is you are copying memory, and one of the keys to efficient IO is reducing the number of times memory is copied.

brianegge
ByteArrayOutputStream is actually exactly what I want (I'm not actually doing any I/O, I just have some complex serialization to do). Thanks!
Seth
Seth, your statement of the question ("putX") implied that you would need methods such as putInt, putDouble, etc., which implied that ByteArrayOutputStream wouldn't be enough for you, hence my answer of ByteArrayDataOutput.
Kevin Bourrillion
+2  A: 

Have a look at Mina IOBuffer http://mina.apache.org/iobuffer.html which is a drop in replacement (it wraps the ByteBuffer)

However , I suggest you allocate more than you need and don't worry about it too much. If you allocate a buffer (esp a direct buffer) the OS gives it virtual memory but it only uses physical memory when its actually used. Virtual memory should be very cheap.

Peter Lawrey
I love the warning on the page: "The main reason why MINA has its own wrapper on top of nio ByteBuffer is to have extensible buffers. This was a very bad decision."
Suppressingfire
+2  A: 

A ByteBuffer cannot really work this way, as its design concept is to be just a view of a specific array, which you may also have a direct reference to. It could not try to swap that array for a larger array without weirdness happening.

What you want to use is a DataOutput. The most convenient way is to use the (pre-release) Guava library:

ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.write(someBytes);
out.writeInt(someInt);
// ...
return out.toByteArray();

But you could also create a DataOutputStream from a ByteArrayOutputStream manually, and just deal with the spurious IOExceptions by chaining them into AssertionErrors.

Kevin Bourrillion
+1  A: 

It may be also worth to have a look at Netty's DynamicChannelBuffer. Things that I find handy are:

  • slice(int index, int length)
  • unsigned operations
  • separated writer and reader indexes

HTH

anonymous
A: 

Another option is to use direct memory with a large buffer. This consumes virtual memory but only uses as much physical memory as you use (by page which is typically 4K)

So if you allocate a buffer of 1 MB, it comsumes 1 MB of virtual memory, but the only OS gives physical pages to the application which is actually uses.

The effect is you see your application using alot of virtual memory but a relatively small amount of resident memory.

Peter Lawrey