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; } }