From fe4af7e32c2b49665bf4f0534872135501929bd6 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Fri, 22 Jul 2016 15:24:31 +0200 Subject: [PATCH] Ensure shared capacity is updated correctly when WeakOrderQueue is collected. Motivation: We use a shared capacity per Stack for all its WeakOrderQueue elements. These relations are stored in a WeakHashMap to allow dropping these if memory pressure arise. The problem is that we not "reclaim" previous reserved space when this happens. This can lead to a Stack which has not shared capacity left which then will lead to an AssertError when we try to allocate a new WeakOderQueue. Modifications: - Ensure we never throw an AssertError if we not have enough space left for a new WeakOrderQueue - Ensure we reclaim space when WeakOrderQueue is collected. Result: No more AssertError possible when new WeakOrderQueue is created and also correctly reclaim space that was reserved from the shared capacity. --- .../src/main/java/io/netty/util/Recycler.java | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/io/netty/util/Recycler.java b/common/src/main/java/io/netty/util/Recycler.java index 4bd3f124e1..19ca5cc34b 100644 --- a/common/src/main/java/io/netty/util/Recycler.java +++ b/common/src/main/java/io/netty/util/Recycler.java @@ -190,7 +190,12 @@ public abstract class Recycler { Map, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get(); WeakOrderQueue queue = delayedRecycled.get(stack); if (queue == null) { - delayedRecycled.put(stack, queue = new WeakOrderQueue(stack, thread)); + queue = WeakOrderQueue.allocate(stack, thread); + if (queue == null) { + // drop object + return; + } + delayedRecycled.put(stack, queue); } queue.add(this); } @@ -225,7 +230,7 @@ public abstract class Recycler { private final int id = ID_GENERATOR.getAndIncrement(); private final AtomicInteger availableSharedCapacity; - WeakOrderQueue(Stack stack, Thread thread) { + private WeakOrderQueue(Stack stack, Thread thread) { head = tail = new Link(); owner = new WeakReference(thread); synchronized (stack) { @@ -237,13 +242,18 @@ public abstract class Recycler { // the WeakHashMap as key. So just store the enclosed AtomicInteger which should allow to have the // Stack itself GCed. availableSharedCapacity = stack.availableSharedCapacity; - - // We allocated a Link so reserve the space - boolean reserved = reserveSpace(LINK_CAPACITY); - assert reserved; } - private boolean reserveSpace(int space) { + /** + * Allocate a new {@link WeakOrderQueue} or return {@code null} if not possible. + */ + static WeakOrderQueue allocate(Stack stack, Thread thread) { + // We allocated a Link so reserve the space + return reserveSpace(stack.availableSharedCapacity, LINK_CAPACITY) + ? new WeakOrderQueue(stack, thread) : null; + } + + private static boolean reserveSpace(AtomicInteger availableSharedCapacity, int space) { assert space >= 0; for (;;) { int available = availableSharedCapacity.get(); @@ -267,7 +277,7 @@ public abstract class Recycler { Link tail = this.tail; int writeIndex; if ((writeIndex = tail.get()) == LINK_CAPACITY) { - if (!reserveSpace(LINK_CAPACITY)) { + if (!reserveSpace(availableSharedCapacity, LINK_CAPACITY)) { // Drop it. return; } @@ -290,7 +300,6 @@ public abstract class Recycler { // transfer as many items as we can from this queue to the stack, returning true if any were transferred @SuppressWarnings("rawtypes") boolean transfer(Stack dst) { - Link head = this.head; if (head == null) { return false; @@ -349,6 +358,22 @@ public abstract class Recycler { return false; } } + + @Override + protected void finalize() throws Throwable { + try { + super.finalize(); + } finally { + // We need to reclaim all space that was reserved by this WeakOrderQueue so we not run out of space in + // the stack. This is needed as we not have a good life-time control over the queue as it is used in a + // WeakHashMap which will drop it at any time. + Link link = head; + while (link != null) { + reclaimSpace(LINK_CAPACITY); + link = link.next; + } + } + } } static final class Stack {