diff --git a/buffer/src/main/java/io/netty/buffer/PoolSubpage.java b/buffer/src/main/java/io/netty/buffer/PoolSubpage.java index 26880ab1bb..62e905c4d0 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolSubpage.java +++ b/buffer/src/main/java/io/netty/buffer/PoolSubpage.java @@ -115,7 +115,13 @@ final class PoolSubpage implements PoolSubpageMetric { if (numAvail ++ == 0) { addToPool(head); - return true; + /* When maxNumElems == 1, the maximum numAvail is also 1. + * Each of these PoolSubpages will go in here when they do free operation. + * If they return true directly from here, then the rest of the code will be unreachable + * and they will not actually be recycled. So return true only on maxNumElems > 1. */ + if (maxNumElems > 1) { + return true; + } } if (numAvail != maxNumElems) { diff --git a/buffer/src/test/java/io/netty/buffer/PooledByteBufAllocatorTest.java b/buffer/src/test/java/io/netty/buffer/PooledByteBufAllocatorTest.java index d23338da9c..dafa83d2b1 100644 --- a/buffer/src/test/java/io/netty/buffer/PooledByteBufAllocatorTest.java +++ b/buffer/src/test/java/io/netty/buffer/PooledByteBufAllocatorTest.java @@ -632,8 +632,8 @@ public class PooledByteBufAllocatorTest extends AbstractByteBufAllocatorTest unwrapIfNeeded(ByteBuf buf) { - return (PooledByteBuf) (buf instanceof PooledByteBuf ? buf : buf.unwrap()); + private static PooledByteBuf unwrapIfNeeded(ByteBuf buf) { + return (PooledByteBuf) (buf instanceof PooledByteBuf ? buf : buf.unwrap()); } @Test @@ -661,4 +661,27 @@ public class PooledByteBufAllocatorTest extends AbstractByteBufAllocatorTest chunk = unwrapIfNeeded(byteBufs[0]).chunk; + + int beforeFreeBytes = chunk.freeBytes(); + for (int i = 0; i < length; i++) { + byteBufs[i].release(); + } + int afterFreeBytes = chunk.freeBytes(); + + assertTrue(beforeFreeBytes < afterFreeBytes); + } }