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;
}
Runnable postTask = null;
try {
doDeregister();
postTask = doDeregister();
} catch (Throwable t) {
logger.warn("Unexpected exception occurred while deregistering a channel.", t);
} finally {
@ -756,6 +757,10 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
// close() calls deregister() again - no need to fire channelUnregistered.
promise.setSuccess();
}
if (postTask != null) {
postTask.run();
}
}
} else {
eventLoop().execute(new Runnable() {
@ -973,11 +978,12 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
/**
* 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
*/
protected void doDeregister() throws Exception {
// NOOP
protected Runnable doDeregister() throws Exception {
return null;
}
/**

View File

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

View File

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

View File

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

View File

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