Cache underlying ByteBuffers and count in ChannelOutboundBuffer.Entry to reduce object creation and so GC pressure

Beside this it also helps to reduce CPU usage as nioBufferCount() is quite expensive when used on CompositeByteBuf which are
nested and contains a lot of components
This commit is contained in:
Norman Maurer 2013-09-26 10:44:42 +02:00
parent 2b9a07cac9
commit b4fa8af079
2 changed files with 31 additions and 12 deletions

View File

@ -790,6 +790,5 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest {
buf.addComponent(buffer().writeByte(1));
assertFalse(buf.isDirect());
}
}

View File

@ -329,24 +329,39 @@ public final class ChannelOutboundBuffer {
return null;
}
Entry entry = buffer[i];
ByteBuf buf = (ByteBuf) m;
final int readerIndex = buf.readerIndex();
final int readableBytes = buf.writerIndex() - readerIndex;
if (readableBytes > 0) {
nioBufferSize += readableBytes;
int count = buf.nioBufferCount();
int count = entry.count;
if (count == -1) {
entry.count = count = buf.nioBufferCount();
}
if (nioBufferCount + count > nioBuffers.length) {
this.nioBuffers = nioBuffers = doubleNioBufferArray(nioBuffers, nioBufferCount);
}
if (buf.isDirect() || !alloc.isDirectBufferPooled()) {
if (buf.nioBufferCount() == 1) {
nioBuffers[nioBufferCount ++] = buf.internalNioBuffer(readerIndex, readableBytes);
if (count == 1) {
ByteBuffer nioBuf = entry.buf;
if (nioBuf == null) {
// cache ByteBuffer as it may need to create a new ByteBuffer instance if its a
// derived buffer
entry.buf = nioBuf = buf.internalNioBuffer(readerIndex, readableBytes);
}
nioBuffers[nioBufferCount ++] = nioBuf;
} else {
nioBufferCount = fillBufferArray(buf, nioBuffers, nioBufferCount);
ByteBuffer[] nioBufs = entry.buffers;
if (nioBufs == null) {
// cached ByteBuffers as they may be expensive to create in terms of Object allocation
entry.buffers = nioBufs = buf.nioBuffers();
}
nioBufferCount = fillBufferArray(nioBufs, nioBuffers, nioBufferCount);
}
} else {
nioBufferCount = fillBufferArrayNonDirect(buffer[i], buf, readerIndex,
nioBufferCount = fillBufferArrayNonDirect(entry, buf, readerIndex,
readableBytes, alloc, nioBuffers, nioBufferCount);
}
}
@ -358,8 +373,7 @@ public final class ChannelOutboundBuffer {
return nioBuffers;
}
private static int fillBufferArray(ByteBuf buf, ByteBuffer[] nioBuffers, int nioBufferCount) {
ByteBuffer[] nioBufs = buf.nioBuffers();
private static int fillBufferArray(ByteBuffer[] nioBufs, ByteBuffer[] nioBuffers, int nioBufferCount) {
for (ByteBuffer nioBuf: nioBufs) {
if (nioBuf == null) {
break;
@ -375,10 +389,10 @@ public final class ChannelOutboundBuffer {
directBuf.writeBytes(buf, readerIndex, readableBytes);
buf.release();
entry.msg = directBuf;
if (nioBufferCount == nioBuffers.length) {
nioBuffers = doubleNioBufferArray(nioBuffers, nioBufferCount);
}
nioBuffers[nioBufferCount ++] = directBuf.internalNioBuffer(0, readableBytes);
// cache ByteBuffer
ByteBuffer nioBuf = entry.buf = directBuf.internalNioBuffer(0, readableBytes);
entry.count = 1;
nioBuffers[nioBufferCount ++] = nioBuf;
return nioBufferCount;
}
@ -529,17 +543,23 @@ public final class ChannelOutboundBuffer {
private static final class Entry {
Object msg;
ByteBuffer[] buffers;
ByteBuffer buf;
ChannelPromise promise;
long progress;
long total;
int pendingSize;
int count = -1;
public void clear() {
buffers = null;
buf = null;
msg = null;
promise = null;
progress = 0;
total = 0;
pendingSize = 0;
count = -1;
}
}