I've been implementing Netty 4 on my app and I've ran into a limitation which I would like to optimize.
I'm using NioSocketChannel where when I receive data, the final object it needs to end up into is a Direct ByteBuffer Native,created as such:
ByteBuffer.allocateDirect(var0).order(ByteOrder.nativeOrder());
This is hard requirement, I can't go around it.
To minimize object allocation, I'm using a ByteBufferPool and my ChannelRead looks something like this:
try{
receivingBuf.writeBytes((ByteBuf) msg);
if(receivingBuf.readableBytes() >= nextPacketLength){
var bb = ByteBufferPoolManager.getByteBuffer();
receivingBuf.readBytes(bb.array(), 0, nextPacketLength-12);
bb.position(0);
bb.limit(nextPacketLength - 12);
MyCustomMethodToProcessData(bb);
}
}
finally
{
((ByteBuf) msg).release();
}
Please ignore the -12 bytes, that is due to the format of my packets. Also, ByteBufferPoolManager.getByteBuffer()
returns a normal heap ByteBuffer.
GOAL: Transfer a specific number of bytes from receivingBuf
into a Direct Native Order allocated ByteBuffer.
I tried to do this:
var bb = ByteBufferPoolManager.getNativeByteBuffer();
receivingBuf.readBytes(bb.array(), 0, nextPacketLength-12);
bb.position(0);
bb.limit(nextPacketLength - 12);
MyCustomMethodToProcessData(bb);
But this doesn't work, as you can't access .array()
on a Direct ByteBuffer. You get exception:
java.lang.UnsupportedOperationException
at java.base/java.nio.ByteBuffer.array(ByteBuffer.java:1471)
If I do:
var bb = ByteBufferPoolManager.getNativeByteBuffer();
receivingBuf.readBytes(bb, 0, nextPacketLength-12);
...
This doesn't exist as an available method on ByteBuf.
Additionally, if I do:
var bb = ByteBufferPoolManager.getNativeByteBuffer();
receivingBuf.readBytes(bb);
...
Will cause an exception, as the Native ByteBuffer is massive (1000000 size), and ByteBuf will attempt to copy over 1 million bytes, while the available bytes on the ByteBuf is way less than that.
One option I've considered, is having a byte[] per channel context, which is used exclusively do to this data transfer, but still, I don't think I will have much improvements vs what I'm doing now.
Any ideas on how I can remove this middle hop in ByteBuf -> Heap ByteBuffer -> Native ByteBuffer
?
You can modify the limit first
Or you can duplicate bb and modify its limit. Don't worry about the overhead, because the duplicate shares the original's content, so the overhead is very small.