diff --git a/common/src/main/java/io/netty/util/Recycler.java b/common/src/main/java/io/netty/util/Recycler.java index edc7672c7c..1e0bc39e26 100644 --- a/common/src/main/java/io/netty/util/Recycler.java +++ b/common/src/main/java/io/netty/util/Recycler.java @@ -36,8 +36,11 @@ public abstract class Recycler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class); + private static final Handle NOOP_HANDLE = new Handle() { }; private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE); private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement(); + // TODO: Some arbitrary large number - should adjust as we get more production experience. + private static final int DEFAULT_INITIAL_MAX_CAPACITY = 262144; private static final int DEFAULT_MAX_CAPACITY; private static final int INITIAL_CAPACITY; @@ -45,15 +48,19 @@ public abstract class Recycler { // In the future, we might have different maxCapacity for different object types. // e.g. io.netty.recycler.maxCapacity.writeTask // io.netty.recycler.maxCapacity.outboundBuffer - int maxCapacity = SystemPropertyUtil.getInt("io.netty.recycler.maxCapacity.default", 0); - if (maxCapacity <= 0) { - // TODO: Some arbitrary large number - should adjust as we get more production experience. - maxCapacity = 262144; + int maxCapacity = SystemPropertyUtil.getInt("io.netty.recycler.maxCapacity.default", + DEFAULT_INITIAL_MAX_CAPACITY); + if (maxCapacity < 0) { + maxCapacity = DEFAULT_INITIAL_MAX_CAPACITY; } DEFAULT_MAX_CAPACITY = maxCapacity; if (logger.isDebugEnabled()) { - logger.debug("-Dio.netty.recycler.maxCapacity.default: {}", DEFAULT_MAX_CAPACITY); + if (DEFAULT_MAX_CAPACITY == 0) { + logger.debug("-Dio.netty.recycler.maxCapacity.default: disabled"); + } else { + logger.debug("-Dio.netty.recycler.maxCapacity.default: {}", DEFAULT_MAX_CAPACITY); + } } INITIAL_CAPACITY = Math.min(DEFAULT_MAX_CAPACITY, 256); @@ -77,6 +84,9 @@ public abstract class Recycler { @SuppressWarnings("unchecked") public final T get() { + if (maxCapacity == 0) { + return newObject(NOOP_HANDLE); + } Stack stack = threadLocal.get(); DefaultHandle handle = stack.pop(); if (handle == null) { @@ -87,6 +97,10 @@ public abstract class Recycler { } public final boolean recycle(T o, Handle handle) { + if (handle == NOOP_HANDLE) { + return false; + } + DefaultHandle h = (DefaultHandle) handle; if (h.stack.parent != this) { return false; diff --git a/common/src/test/java/io/netty/util/RecyclerTest.java b/common/src/test/java/io/netty/util/RecyclerTest.java index e90957034c..cae4cc2e34 100644 --- a/common/src/test/java/io/netty/util/RecyclerTest.java +++ b/common/src/test/java/io/netty/util/RecyclerTest.java @@ -40,6 +40,15 @@ public class RecyclerTest { object2.recycle(); } + @Test + public void testRecycleDisable() { + DisabledRecyclableObject object = DisabledRecyclableObject.newInstance(); + object.recycle(); + DisabledRecyclableObject object2 = DisabledRecyclableObject.newInstance(); + assertNotSame(object, object2); + object2.recycle(); + } + static final class RecyclableObject { private static final Recycler RECYCLER = new Recycler() { @@ -64,6 +73,30 @@ public class RecyclerTest { } } + static final class DisabledRecyclableObject { + + private static final Recycler RECYCLER = new Recycler(-1) { + @Override + protected DisabledRecyclableObject newObject(Handle handle) { + return new DisabledRecyclableObject(handle); + } + }; + + private final Recycler.Handle handle; + + private DisabledRecyclableObject(Recycler.Handle handle) { + this.handle = handle; + } + + public static DisabledRecyclableObject newInstance() { + return RECYCLER.get(); + } + + public void recycle() { + RECYCLER.recycle(this, handle); + } + } + /** * Test to make sure bug #2848 never happens again * https://github.com/netty/netty/issues/2848