From 948d4a9ec58aef092c84eb76e672fd06e81cc13c Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Mon, 28 Jan 2019 19:45:38 +0100 Subject: [PATCH] Minimize memory footprint for AbstractChannelHandlerContext for handlers that execute in the EventExecutor. (#8786) Motivation: We cache the Runnable for some tasks to reduce GC pressure in 4 different fields. This gives overhead in terms of memory usage in all cases, even if we always execute in the EventExecutor (which is the case most of the times). Modifications: Move the 4 fields to another class and only have one reference to this in AbstractChannelHandlerContext. This gives a small overhead in the case of execution that is done outside of the EventExecutor but reduce memory footprint in the more likily execution case. Result: Less memory used per AbstractChannelHandlerContext in most cases. --- .../AbstractChannelHandlerContext.java | 89 ++++++++++--------- 1 file changed, 49 insertions(+), 40 deletions(-) diff --git a/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java b/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java index 6abf529afc..f24771a50e 100644 --- a/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java +++ b/transport/src/main/java/io/netty/channel/AbstractChannelHandlerContext.java @@ -76,10 +76,7 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap // Lazily instantiated tasks used to trigger events to a handler with different executor. // There is no need to make this volatile as at worse it will just create a few more instances then needed. - private Runnable invokeChannelReadCompleteTask; - private Runnable invokeReadTask; - private Runnable invokeChannelWritableStateChangedTask; - private Runnable invokeFlushTask; + private Tasks invokeTasks; private volatile int handlerState = INIT; @@ -379,16 +376,11 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap if (executor.inEventLoop()) { next.invokeChannelReadComplete(); } else { - Runnable task = next.invokeChannelReadCompleteTask; - if (task == null) { - next.invokeChannelReadCompleteTask = task = new Runnable() { - @Override - public void run() { - next.invokeChannelReadComplete(); - } - }; + Tasks tasks = next.invokeTasks; + if (tasks == null) { + next.invokeTasks = tasks = new Tasks(next); } - executor.execute(task); + executor.execute(tasks.invokeChannelReadCompleteTask); } } @@ -415,16 +407,11 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap if (executor.inEventLoop()) { next.invokeChannelWritabilityChanged(); } else { - Runnable task = next.invokeChannelWritableStateChangedTask; - if (task == null) { - next.invokeChannelWritableStateChangedTask = task = new Runnable() { - @Override - public void run() { - next.invokeChannelWritabilityChanged(); - } - }; + Tasks tasks = next.invokeTasks; + if (tasks == null) { + next.invokeTasks = tasks = new Tasks(next); } - executor.execute(task); + executor.execute(tasks.invokeChannelWritableStateChangedTask); } } @@ -672,16 +659,11 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap if (executor.inEventLoop()) { next.invokeRead(); } else { - Runnable task = next.invokeReadTask; - if (task == null) { - next.invokeReadTask = task = new Runnable() { - @Override - public void run() { - next.invokeRead(); - } - }; + Tasks tasks = next.invokeTasks; + if (tasks == null) { + next.invokeTasks = tasks = new Tasks(next); } - executor.execute(task); + executor.execute(tasks.invokeReadTask); } return this; @@ -734,16 +716,11 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap if (executor.inEventLoop()) { next.invokeFlush(); } else { - Runnable task = next.invokeFlushTask; - if (task == null) { - next.invokeFlushTask = task = new Runnable() { - @Override - public void run() { - next.invokeFlush(); - } - }; + Tasks tasks = next.invokeTasks; + if (tasks == null) { + next.invokeTasks = tasks = new Tasks(next); } - safeExecute(executor, task, channel().voidPromise(), null); + safeExecute(executor, tasks.invokeFlushTask, channel().voidPromise(), null); } return this; @@ -1162,4 +1139,36 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap ctx.invokeFlush(); } } + + private static final class Tasks { + private final AbstractChannelHandlerContext next; + private final Runnable invokeChannelReadCompleteTask = new Runnable() { + @Override + public void run() { + next.invokeChannelReadComplete(); + } + }; + private final Runnable invokeReadTask = new Runnable() { + @Override + public void run() { + next.invokeRead(); + } + }; + private final Runnable invokeChannelWritableStateChangedTask = new Runnable() { + @Override + public void run() { + next.invokeChannelWritabilityChanged(); + } + }; + private final Runnable invokeFlushTask = new Runnable() { + @Override + public void run() { + next.invokeFlush(); + } + }; + + Tasks(AbstractChannelHandlerContext next) { + this.next = next; + } + } }