diff --git a/common/src/main/java/io/netty/util/Recycler.java b/common/src/main/java/io/netty/util/Recycler.java index 1e002f7d0b..96710bad5e 100644 --- a/common/src/main/java/io/netty/util/Recycler.java +++ b/common/src/main/java/io/netty/util/Recycler.java @@ -54,6 +54,7 @@ public abstract class Recycler { private static final int MAX_DELAYED_QUEUES_PER_THREAD; private static final int LINK_CAPACITY; private static final int RATIO; + private static final int DELAYED_QUEUE_RATIO; static { // In the future, we might have different maxCapacity for different object types. @@ -83,6 +84,7 @@ public abstract class Recycler { // This should help to slowly increase the capacity of the recycler while not be too sensitive to allocation // bursts. RATIO = max(0, SystemPropertyUtil.getInt("io.netty.recycler.ratio", 8)); + DELAYED_QUEUE_RATIO = max(0, SystemPropertyUtil.getInt("io.netty.recycler.delayedQueue.ratio", RATIO)); if (logger.isDebugEnabled()) { if (DEFAULT_MAX_CAPACITY_PER_THREAD == 0) { @@ -90,11 +92,13 @@ public abstract class Recycler { logger.debug("-Dio.netty.recycler.maxSharedCapacityFactor: disabled"); logger.debug("-Dio.netty.recycler.linkCapacity: disabled"); logger.debug("-Dio.netty.recycler.ratio: disabled"); + logger.debug("-Dio.netty.recycler.delayedQueue.ratio: disabled"); } else { logger.debug("-Dio.netty.recycler.maxCapacityPerThread: {}", DEFAULT_MAX_CAPACITY_PER_THREAD); logger.debug("-Dio.netty.recycler.maxSharedCapacityFactor: {}", MAX_SHARED_CAPACITY_FACTOR); logger.debug("-Dio.netty.recycler.linkCapacity: {}", LINK_CAPACITY); logger.debug("-Dio.netty.recycler.ratio: {}", RATIO); + logger.debug("-Dio.netty.recycler.delayedQueue.ratio: {}", DELAYED_QUEUE_RATIO); } } @@ -105,12 +109,13 @@ public abstract class Recycler { private final int maxSharedCapacityFactor; private final int interval; private final int maxDelayedQueuesPerThread; + private final int delayedQueueInterval; private final FastThreadLocal> threadLocal = new FastThreadLocal>() { @Override protected Stack initialValue() { return new Stack<>(Recycler.this, Thread.currentThread(), maxCapacityPerThread, maxSharedCapacityFactor, - interval, maxDelayedQueuesPerThread); + interval, maxDelayedQueuesPerThread, delayedQueueInterval); } @Override @@ -138,7 +143,14 @@ public abstract class Recycler { protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor, int ratio, int maxDelayedQueuesPerThread) { + this(maxCapacityPerThread, maxSharedCapacityFactor, ratio, maxDelayedQueuesPerThread, + DELAYED_QUEUE_RATIO); + } + + protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor, + int ratio, int maxDelayedQueuesPerThread, int delayedQueueRatio) { interval = max(0, ratio); + delayedQueueInterval = max(0, delayedQueueRatio); if (maxCapacityPerThread <= 0) { this.maxCapacityPerThread = 0; this.maxSharedCapacityFactor = 1; @@ -328,7 +340,7 @@ public abstract class Recycler { // Stack itself GCed. head = new Head(stack.availableSharedCapacity); head.link = tail; - interval = stack.interval; + interval = stack.delayedQueueInterval; handleRecycleCount = interval; // Start at interval so the first one will be recycled. } @@ -486,6 +498,7 @@ public abstract class Recycler { private final int maxCapacity; private final int interval; + private final int delayedQueueInterval; DefaultHandle[] elements; int size; private int handleRecycleCount; @@ -493,13 +506,14 @@ public abstract class Recycler { private volatile WeakOrderQueue head; Stack(Recycler parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor, - int interval, int maxDelayedQueues) { + int interval, int maxDelayedQueues, int delayedQueueInterval) { this.parent = parent; threadRef = new WeakReference<>(thread); this.maxCapacity = maxCapacity; availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY)); elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)]; this.interval = interval; + this.delayedQueueInterval = delayedQueueInterval; handleRecycleCount = interval; // Start at interval so the first one will be recycled. this.maxDelayedQueues = maxDelayedQueues; } diff --git a/common/src/test/java/io/netty/util/RecyclerTest.java b/common/src/test/java/io/netty/util/RecyclerTest.java index b226c84fac..c2cc38c8ea 100644 --- a/common/src/test/java/io/netty/util/RecyclerTest.java +++ b/common/src/test/java/io/netty/util/RecyclerTest.java @@ -27,13 +27,14 @@ import static org.junit.Assert.*; public class RecyclerTest { private static Recycler newRecycler(int maxCapacityPerThread) { - return newRecycler(maxCapacityPerThread, 2, 8, 2); + return newRecycler(maxCapacityPerThread, 2, 8, 2, 8); } private static Recycler newRecycler(int maxCapacityPerThread, int maxSharedCapacityFactor, - int ratio, int maxDelayedQueuesPerThread) { + int ratio, int maxDelayedQueuesPerThread, + int delayedQueueRatio) { return new Recycler(maxCapacityPerThread, maxSharedCapacityFactor, ratio, - maxDelayedQueuesPerThread) { + maxDelayedQueuesPerThread, delayedQueueRatio) { @Override protected HandledObject newObject( Recycler.Handle handle) { @@ -130,7 +131,7 @@ public class RecyclerTest { @Test public void testRecycleDisableDrop() { - Recycler recycler = newRecycler(1024, 2, 0, 2); + Recycler recycler = newRecycler(1024, 2, 0, 2, 0); HandledObject object = recycler.get(); object.recycle(); HandledObject object2 = recycler.get(); @@ -141,6 +142,27 @@ public class RecyclerTest { object3.recycle(); } + @Test + public void testRecycleDisableDelayedQueueDrop() throws Exception { + final Recycler recycler = newRecycler(1024, 2, 1, 2, 0); + final HandledObject o = recycler.get(); + final HandledObject o2 = recycler.get(); + final HandledObject o3 = recycler.get(); + final Thread thread = new Thread() { + @Override + public void run() { + o.recycle(); + o2.recycle(); + o3.recycle(); + } + }; + thread.start(); + thread.join(); + // In reverse order + assertSame(o3, recycler.get()); + assertSame(o, recycler.get()); + } + /** * Test to make sure bug #2848 never happens again * https://github.com/netty/netty/issues/2848 @@ -173,13 +195,7 @@ public class RecyclerTest { @Test public void testRecycleAtDifferentThread() throws Exception { - final Recycler recycler = new Recycler(256, 10, 2, 10) { - @Override - protected HandledObject newObject(Recycler.Handle handle) { - return new HandledObject(handle); - } - }; - + final Recycler recycler = newRecycler(256, 10, 2, 10, 2); final HandledObject o = recycler.get(); final HandledObject o2 = recycler.get();