Fix memory leak in DefaultCompositeByteBuf when a component is another CompositeByteBuf / Allow retain() and release() on a derived buffer
This commit is contained in:
parent
60d9984db1
commit
0f351d2c47
@ -33,22 +33,24 @@ public abstract class AbstractDerivedByteBuf extends AbstractByteBuf {
|
||||
|
||||
@Override
|
||||
public final ByteBuf retain() {
|
||||
unwrap().retain();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ByteBuf retain(int increment) {
|
||||
unwrap().retain(increment);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean release() {
|
||||
return false;
|
||||
return unwrap().release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean release(int decrement) {
|
||||
return false;
|
||||
return unwrap().release(decrement);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -228,13 +228,18 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf
|
||||
List<Component> list = compositeBuf.components;
|
||||
ByteBuf[] array = new ByteBuf[list.size()];
|
||||
for (int i = 0; i < array.length; i ++) {
|
||||
ByteBuf slice = list.get(i).buf;
|
||||
ByteBuf buf;
|
||||
for (buf = slice; buf.unwrap() != null; buf = buf.unwrap()) {
|
||||
continue;
|
||||
}
|
||||
buf.retain();
|
||||
array[i] = slice;
|
||||
array[i] = list.get(i).buf.retain();
|
||||
}
|
||||
compositeBuf.release();
|
||||
return addComponents0(cIndex, array);
|
||||
}
|
||||
|
||||
if (buffers instanceof CompositeByteBuf) {
|
||||
CompositeByteBuf compositeBuf = (CompositeByteBuf) buffers;
|
||||
final int nComponents = compositeBuf.numComponents();
|
||||
ByteBuf[] array = new ByteBuf[nComponents];
|
||||
for (int i = 0; i < nComponents; i ++) {
|
||||
array[i] = compositeBuf.component(i).retain();
|
||||
}
|
||||
compositeBuf.release();
|
||||
return addComponents0(cIndex, array);
|
||||
@ -1258,11 +1263,6 @@ public class DefaultCompositeByteBuf extends AbstractReferenceCountedByteBuf
|
||||
|
||||
void freeIfNecessary() {
|
||||
// Unwrap so that we can free slices, too.
|
||||
ByteBuf buf;
|
||||
for (buf = this.buf; buf.unwrap() != null; buf = buf.unwrap()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (suspendedDeallocations == null) {
|
||||
buf.release(); // We should not get a NPE here. If so, it must be a bug.
|
||||
} else {
|
||||
|
@ -72,13 +72,8 @@ public abstract class AbstractByteBufTest {
|
||||
@After
|
||||
public void dispose() {
|
||||
if (buffer != null) {
|
||||
if (buffer.unwrap() == null) {
|
||||
assertThat(buffer.release(), is(true));
|
||||
assertThat(buffer.refCnt(), is(0));
|
||||
} else {
|
||||
assertThat(buffer.release(), is(false));
|
||||
assertThat(buffer.refCnt(), is(1));
|
||||
}
|
||||
assertThat(buffer.release(), is(true));
|
||||
assertThat(buffer.refCnt(), is(0));
|
||||
|
||||
try {
|
||||
buffer.release();
|
||||
|
@ -16,16 +16,19 @@
|
||||
package io.netty.buffer;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ScatteringByteChannel;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
|
||||
import static io.netty.buffer.Unpooled.*;
|
||||
import static org.junit.Assert.*;
|
||||
@ -36,6 +39,27 @@ import static org.junit.Assert.*;
|
||||
@SuppressWarnings("ZeroLengthArrayAllocation")
|
||||
public class UnpooledTest {
|
||||
|
||||
private static final Queue<ByteBuf> freeLaterQueue = new ArrayDeque<ByteBuf>();
|
||||
|
||||
protected ByteBuf freeLater(ByteBuf buf) {
|
||||
freeLaterQueue.add(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
for (;;) {
|
||||
ByteBuf buf = freeLaterQueue.poll();
|
||||
if (buf == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf.refCnt() > 0) {
|
||||
buf.release(buf.refCnt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompositeWrappedBuffer() {
|
||||
ByteBuf header = buffer(12);
|
||||
@ -127,22 +151,22 @@ public class UnpooledTest {
|
||||
@Test
|
||||
public void testCompare() {
|
||||
List<ByteBuf> expected = new ArrayList<ByteBuf>();
|
||||
expected.add(wrappedBuffer(new byte[] { 1 }));
|
||||
expected.add(wrappedBuffer(new byte[] { 1, 2 }));
|
||||
expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }));
|
||||
expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }));
|
||||
expected.add(wrappedBuffer(new byte[] { 2 }));
|
||||
expected.add(wrappedBuffer(new byte[] { 2, 3 }));
|
||||
expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }));
|
||||
expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }));
|
||||
expected.add(wrappedBuffer(new byte[] { 2, 3, 4 }, 1, 1));
|
||||
expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4 }, 2, 2));
|
||||
expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, 1, 10));
|
||||
expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, 2, 12));
|
||||
expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5 }, 2, 1));
|
||||
expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5 }, 3, 2));
|
||||
expected.add(wrappedBuffer(new byte[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, 2, 10));
|
||||
expected.add(wrappedBuffer(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, 3, 12));
|
||||
expected.add(wrappedBuffer(new byte[]{1}));
|
||||
expected.add(wrappedBuffer(new byte[]{1, 2}));
|
||||
expected.add(wrappedBuffer(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}));
|
||||
expected.add(wrappedBuffer(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}));
|
||||
expected.add(wrappedBuffer(new byte[]{2}));
|
||||
expected.add(wrappedBuffer(new byte[]{2, 3}));
|
||||
expected.add(wrappedBuffer(new byte[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11}));
|
||||
expected.add(wrappedBuffer(new byte[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}));
|
||||
expected.add(wrappedBuffer(new byte[]{2, 3, 4}, 1, 1));
|
||||
expected.add(wrappedBuffer(new byte[]{1, 2, 3, 4}, 2, 2));
|
||||
expected.add(wrappedBuffer(new byte[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 1, 10));
|
||||
expected.add(wrappedBuffer(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 2, 12));
|
||||
expected.add(wrappedBuffer(new byte[]{2, 3, 4, 5}, 2, 1));
|
||||
expected.add(wrappedBuffer(new byte[]{1, 2, 3, 4, 5}, 3, 2));
|
||||
expected.add(wrappedBuffer(new byte[]{2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 2, 10));
|
||||
expected.add(wrappedBuffer(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 3, 12));
|
||||
|
||||
for (int i = 0; i < expected.size(); i ++) {
|
||||
for (int j = 0; j < expected.size(); j ++) {
|
||||
@ -216,7 +240,7 @@ public class UnpooledTest {
|
||||
|
||||
@Test
|
||||
public void testWrappedBuffer() {
|
||||
assertEquals(16, wrappedBuffer(ByteBuffer.allocateDirect(16)).capacity());
|
||||
assertEquals(16, freeLater(wrappedBuffer(ByteBuffer.allocateDirect(16))).capacity());
|
||||
|
||||
assertEquals(
|
||||
wrappedBuffer(new byte[] { 1, 2, 3 }),
|
||||
@ -224,10 +248,10 @@ public class UnpooledTest {
|
||||
|
||||
assertEquals(
|
||||
wrappedBuffer(new byte[] { 1, 2, 3 }),
|
||||
wrappedBuffer(
|
||||
freeLater(wrappedBuffer(
|
||||
new byte[] { 1 },
|
||||
new byte[] { 2 },
|
||||
new byte[] { 3 }));
|
||||
new byte[] { 3 })));
|
||||
|
||||
assertEquals(
|
||||
wrappedBuffer(new byte[] { 1, 2, 3 }),
|
||||
@ -237,10 +261,10 @@ public class UnpooledTest {
|
||||
|
||||
assertEquals(
|
||||
wrappedBuffer(new byte[] { 1, 2, 3 }),
|
||||
wrappedBuffer(
|
||||
freeLater(wrappedBuffer(
|
||||
wrappedBuffer(new byte[] { 1 }),
|
||||
wrappedBuffer(new byte[] { 2 }),
|
||||
wrappedBuffer(new byte[] { 3 })));
|
||||
wrappedBuffer(new byte[] { 3 }))));
|
||||
|
||||
assertEquals(
|
||||
wrappedBuffer(new byte[] { 1, 2, 3 }),
|
||||
@ -250,10 +274,10 @@ public class UnpooledTest {
|
||||
|
||||
assertEquals(
|
||||
wrappedBuffer(new byte[] { 1, 2, 3 }),
|
||||
wrappedBuffer(
|
||||
freeLater(wrappedBuffer(
|
||||
ByteBuffer.wrap(new byte[] { 1 }),
|
||||
ByteBuffer.wrap(new byte[] { 2 }),
|
||||
ByteBuffer.wrap(new byte[] { 3 })));
|
||||
ByteBuffer.wrap(new byte[] { 3 }))));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user