MemoryRegionCache$Entry objects are not recycled
Netty Version: 4.0.30.Final

MemoryRegionCache$Entry instances are allocated from a Recycler but not recycled when done using them, leading to a lot of GCed objects.

buffer/src/main/java/io/netty/buffer/PoolThreadCache.java
buffer/src/main/java/io/netty/buffer/PoolThreadCache.java
diff --git a/buffer/src/main/java/io/netty/buffer/PoolThreadCache.java b/buffer/src/main/java/io/netty/buffer/PoolThreadCache.java
index 3792c3e65ae..425f657ca96 100644
--- a/buffer/src/main/java/io/netty/buffer/PoolThreadCache.java
+++ b/buffer/src/main/java/io/netty/buffer/PoolThreadCache.java
@@ -386,7 +386,14 @@ protected abstract void initBuf(PoolChunk<T> chunk, long handle,
          */
         @SuppressWarnings("unchecked")
         public final boolean add(PoolChunk<T> chunk, long handle) {
-            return queue.offer(newEntry(chunk, handle));
+            Entry<T> entry = newEntry(chunk, handle);
+            boolean queued = queue.offer(entry);
+            if (!queued) {
+                // If it was not possible to cache the chunk, immediately recycle the entry
+                entry.recycle();
+            }
+
+            return queued;
         }
 
         /**
@@ -398,6 +405,7 @@ public final boolean allocate(PooledByteBuf<T> buf, int reqCapacity) {
                 return false;
             }
             initBuf(entry.chunk, entry.handle, buf, reqCapacity);
+            entry.recycle();
 
             // allocations is not thread-safe which is fine as this is only called from the same thread all time.
             ++ allocations;
