Fix memory leak in AbstractEmbeddedChannel

- Allow a transport implementation to perform an arbitrary task when a channel has been deregistered completely
This commit is contained in:
Trustin Lee 2013-03-14 15:51:33 +09:00
parent d2b137649d
commit 70a51bcd8d
5 changed files with 24 additions and 10 deletions

View File

@ -741,8 +741,9 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
return; return;
} }
Runnable postTask = null;
try { try {
doDeregister(); postTask = doDeregister();
} catch (Throwable t) { } catch (Throwable t) {
logger.warn("Unexpected exception occurred while deregistering a channel.", t); logger.warn("Unexpected exception occurred while deregistering a channel.", t);
} finally { } finally {
@ -756,6 +757,10 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
// close() calls deregister() again - no need to fire channelUnregistered. // close() calls deregister() again - no need to fire channelUnregistered.
promise.setSuccess(); promise.setSuccess();
} }
if (postTask != null) {
postTask.run();
}
} }
} else { } else {
eventLoop().execute(new Runnable() { eventLoop().execute(new Runnable() {
@ -973,11 +978,12 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
/** /**
* Deregister the {@link Channel} from its {@link EventLoop}. * Deregister the {@link Channel} from its {@link EventLoop}.
* You can return a {@link Runnable} which will be run as post-task of the registration process.
* *
* Sub-classes may override this method * Sub-classes may override this method
*/ */
protected void doDeregister() throws Exception { protected Runnable doDeregister() throws Exception {
// NOOP return null;
} }
/** /**

View File

@ -225,8 +225,13 @@ public abstract class AbstractEmbeddedChannel<O> extends AbstractChannel {
} }
@Override @Override
protected void doDeregister() throws Exception { protected Runnable doDeregister() throws Exception {
// NOOP return new Runnable() {
@Override
public void run() {
runPendingTasks();
}
};
} }
@Override @Override

View File

@ -26,8 +26,8 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelConfig; import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.EventLoop; import io.netty.channel.EventLoop;
import io.netty.util.concurrent.SingleThreadEventExecutor;
import io.netty.channel.SingleThreadEventLoop; import io.netty.channel.SingleThreadEventLoop;
import io.netty.util.concurrent.SingleThreadEventExecutor;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.nio.channels.AlreadyConnectedException; import java.nio.channels.AlreadyConnectedException;
@ -201,11 +201,12 @@ public class LocalChannel extends AbstractChannel {
} }
@Override @Override
protected void doDeregister() throws Exception { protected Runnable doDeregister() throws Exception {
if (isOpen()) { if (isOpen()) {
unsafe().close(unsafe().voidFuture()); unsafe().close(unsafe().voidFuture());
} }
((SingleThreadEventExecutor) eventLoop()).removeShutdownHook(shutdownHook); ((SingleThreadEventExecutor) eventLoop()).removeShutdownHook(shutdownHook);
return null;
} }
@Override @Override

View File

@ -22,8 +22,8 @@ import io.netty.channel.ChannelPipeline;
import io.netty.channel.DefaultChannelConfig; import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.EventLoop; import io.netty.channel.EventLoop;
import io.netty.channel.ServerChannel; import io.netty.channel.ServerChannel;
import io.netty.util.concurrent.SingleThreadEventExecutor;
import io.netty.channel.SingleThreadEventLoop; import io.netty.channel.SingleThreadEventLoop;
import io.netty.util.concurrent.SingleThreadEventExecutor;
import java.net.SocketAddress; import java.net.SocketAddress;
@ -126,8 +126,9 @@ public class LocalServerChannel extends AbstractServerChannel {
} }
@Override @Override
protected void doDeregister() throws Exception { protected Runnable doDeregister() throws Exception {
((SingleThreadEventExecutor) eventLoop()).removeShutdownHook(shutdownHook); ((SingleThreadEventExecutor) eventLoop()).removeShutdownHook(shutdownHook);
return null;
} }
@Override @Override

View File

@ -273,8 +273,9 @@ public abstract class AbstractNioChannel extends AbstractChannel {
} }
@Override @Override
protected void doDeregister() throws Exception { protected Runnable doDeregister() throws Exception {
eventLoop().cancel(selectionKey()); eventLoop().cancel(selectionKey());
return null;
} }
@Override @Override