From b4fa8af0791b3a31a91ea8112175adf6493b834b Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Thu, 26 Sep 2013 10:44:42 +0200 Subject: [PATCH] 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 --- .../buffer/AbstractCompositeByteBufTest.java | 1 - .../netty/channel/ChannelOutboundBuffer.java | 42 ++++++++++++++----- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java b/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java index a3523ed72a..f98c223be6 100644 --- a/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java +++ b/buffer/src/test/java/io/netty/buffer/AbstractCompositeByteBufTest.java @@ -790,6 +790,5 @@ public abstract class AbstractCompositeByteBufTest extends AbstractByteBufTest { buf.addComponent(buffer().writeByte(1)); assertFalse(buf.isDirect()); - } } diff --git a/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java b/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java index 63804dfe1a..eb4ff0ff03 100644 --- a/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java +++ b/transport/src/main/java/io/netty/channel/ChannelOutboundBuffer.java @@ -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; } }