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)); buf.addComponent(buffer().writeByte(1));
assertFalse(buf.isDirect()); assertFalse(buf.isDirect());
} }
} }

View File

@ -329,24 +329,39 @@ public final class ChannelOutboundBuffer {
return null; return null;
} }
Entry entry = buffer[i];
ByteBuf buf = (ByteBuf) m; ByteBuf buf = (ByteBuf) m;
final int readerIndex = buf.readerIndex(); final int readerIndex = buf.readerIndex();
final int readableBytes = buf.writerIndex() - readerIndex; final int readableBytes = buf.writerIndex() - readerIndex;
if (readableBytes > 0) { if (readableBytes > 0) {
nioBufferSize += readableBytes; nioBufferSize += readableBytes;
int count = buf.nioBufferCount(); int count = entry.count;
if (count == -1) {
entry.count = count = buf.nioBufferCount();
}
if (nioBufferCount + count > nioBuffers.length) { if (nioBufferCount + count > nioBuffers.length) {
this.nioBuffers = nioBuffers = doubleNioBufferArray(nioBuffers, nioBufferCount); this.nioBuffers = nioBuffers = doubleNioBufferArray(nioBuffers, nioBufferCount);
} }
if (buf.isDirect() || !alloc.isDirectBufferPooled()) { if (buf.isDirect() || !alloc.isDirectBufferPooled()) {
if (buf.nioBufferCount() == 1) { if (count == 1) {
nioBuffers[nioBufferCount ++] = buf.internalNioBuffer(readerIndex, readableBytes); 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 { } 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 { } else {
nioBufferCount = fillBufferArrayNonDirect(buffer[i], buf, readerIndex, nioBufferCount = fillBufferArrayNonDirect(entry, buf, readerIndex,
readableBytes, alloc, nioBuffers, nioBufferCount); readableBytes, alloc, nioBuffers, nioBufferCount);
} }
} }
@ -358,8 +373,7 @@ public final class ChannelOutboundBuffer {
return nioBuffers; return nioBuffers;
} }
private static int fillBufferArray(ByteBuf buf, ByteBuffer[] nioBuffers, int nioBufferCount) { private static int fillBufferArray(ByteBuffer[] nioBufs, ByteBuffer[] nioBuffers, int nioBufferCount) {
ByteBuffer[] nioBufs = buf.nioBuffers();
for (ByteBuffer nioBuf: nioBufs) { for (ByteBuffer nioBuf: nioBufs) {
if (nioBuf == null) { if (nioBuf == null) {
break; break;
@ -375,10 +389,10 @@ public final class ChannelOutboundBuffer {
directBuf.writeBytes(buf, readerIndex, readableBytes); directBuf.writeBytes(buf, readerIndex, readableBytes);
buf.release(); buf.release();
entry.msg = directBuf; entry.msg = directBuf;
if (nioBufferCount == nioBuffers.length) { // cache ByteBuffer
nioBuffers = doubleNioBufferArray(nioBuffers, nioBufferCount); ByteBuffer nioBuf = entry.buf = directBuf.internalNioBuffer(0, readableBytes);
} entry.count = 1;
nioBuffers[nioBufferCount ++] = directBuf.internalNioBuffer(0, readableBytes); nioBuffers[nioBufferCount ++] = nioBuf;
return nioBufferCount; return nioBufferCount;
} }
@ -529,17 +543,23 @@ public final class ChannelOutboundBuffer {
private static final class Entry { private static final class Entry {
Object msg; Object msg;
ByteBuffer[] buffers;
ByteBuffer buf;
ChannelPromise promise; ChannelPromise promise;
long progress; long progress;
long total; long total;
int pendingSize; int pendingSize;
int count = -1;
public void clear() { public void clear() {
buffers = null;
buf = null;
msg = null; msg = null;
promise = null; promise = null;
progress = 0; progress = 0;
total = 0; total = 0;
pendingSize = 0; pendingSize = 0;
count = -1;
} }
} }