From 5986c229c463f064e7b787a4547c0689d2302a03 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Fri, 16 Sep 2016 19:43:51 -0700 Subject: [PATCH] [#5833] Ensure direct memory is released when DirectPoolArena is collected Motivation: We need to ensure we release all direct memory once the DirectPoolArena is collected. Otherwise we may never reclaim the memory and so leak memory. Modifications: Ensure we destroy all PoolChunk memory when DirectPoolArena is collected. Result: Free up unreleased memory when DirectPoolArena is collected. --- .../main/java/io/netty/buffer/PoolArena.java | 23 +++++++++++++++++++ .../main/java/io/netty/buffer/PoolChunk.java | 4 ++++ .../java/io/netty/buffer/PoolChunkList.java | 10 +++++++- .../java/io/netty/buffer/PoolSubpage.java | 6 +++++ 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/buffer/src/main/java/io/netty/buffer/PoolArena.java b/buffer/src/main/java/io/netty/buffer/PoolArena.java index a8e856b947..0b87a96f8d 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolArena.java +++ b/buffer/src/main/java/io/netty/buffer/PoolArena.java @@ -617,6 +617,29 @@ abstract class PoolArena implements PoolArenaMetric { } } + @Override + protected final void finalize() throws Throwable { + try { + super.finalize(); + } finally { + destroyPoolSubPages(smallSubpagePools); + destroyPoolSubPages(tinySubpagePools); + destroyPoolChunkLists(qInit, q000, q025, q050, q075, q100); + } + } + + private static void destroyPoolSubPages(PoolSubpage[] pages) { + for (PoolSubpage page : pages) { + page.destroy(); + } + } + + private void destroyPoolChunkLists(PoolChunkList... chunkLists) { + for (PoolChunkList chunkList: chunkLists) { + chunkList.destroy(this); + } + } + static final class HeapArena extends PoolArena { HeapArena(PooledByteBufAllocator parent, int pageSize, int maxOrder, int pageShifts, int chunkSize) { diff --git a/buffer/src/main/java/io/netty/buffer/PoolChunk.java b/buffer/src/main/java/io/netty/buffer/PoolChunk.java index 18dfd77078..dbc690236c 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolChunk.java +++ b/buffer/src/main/java/io/netty/buffer/PoolChunk.java @@ -461,4 +461,8 @@ final class PoolChunk implements PoolChunkMetric { .append(')') .toString(); } + + void destroy() { + arena.destroyChunk(this); + } } diff --git a/buffer/src/main/java/io/netty/buffer/PoolChunkList.java b/buffer/src/main/java/io/netty/buffer/PoolChunkList.java index 9573dedddc..287c50d4ab 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolChunkList.java +++ b/buffer/src/main/java/io/netty/buffer/PoolChunkList.java @@ -31,7 +31,6 @@ final class PoolChunkList implements PoolChunkListMetric { private final int minUsage; private final int maxUsage; private final int maxCapacity; - private PoolChunk head; // This is only update once when create the linked like list of PoolChunkList in PoolArena constructor. @@ -223,4 +222,13 @@ final class PoolChunkList implements PoolChunkListMetric { return buf.toString(); } + + void destroy(PoolArena arena) { + PoolChunk chunk = head; + while (chunk != null) { + arena.destroyChunk(chunk); + chunk = chunk.next; + } + head = null; + } } diff --git a/buffer/src/main/java/io/netty/buffer/PoolSubpage.java b/buffer/src/main/java/io/netty/buffer/PoolSubpage.java index 0f7cbd0e48..e78ef31099 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolSubpage.java +++ b/buffer/src/main/java/io/netty/buffer/PoolSubpage.java @@ -227,4 +227,10 @@ final class PoolSubpage implements PoolSubpageMetric { public int pageSize() { return pageSize; } + + void destroy() { + if (chunk != null) { + chunk.destroy(); + } + } }