Prevent memory leak when SimpleChannelPools are destroyed (#9760)
Motivation: https://github.com/netty/netty/pull/9548 introduced a change that creates a new AttributeKey for each SimpleChannelPool instance created. AttributeKeys are cached statically in a ConstantPool by the AttributeKey.newInstance method. Because of this, creating a SimpleChannelPool instance will allocate memory that will never be released, even after the SimpleChannelPool is closed. Modifications: This change goes back to a single AttributeKey per SimpleChannelPool, just using a more specific name to reduce the chance of conflicts with user code. Result: No memory is leaked after a SimpleChannelPool instance is created and destroyed.
This commit is contained in:
parent
b381cb253a
commit
394e7f0287
@ -39,8 +39,8 @@ import static io.netty.util.internal.ObjectUtil.*;
|
||||
*
|
||||
*/
|
||||
public class SimpleChannelPool implements ChannelPool {
|
||||
private final AttributeKey<SimpleChannelPool> poolKey = AttributeKey.newInstance("channelPool." +
|
||||
System.identityHashCode(this));
|
||||
private static final AttributeKey<SimpleChannelPool> POOL_KEY =
|
||||
AttributeKey.newInstance("io.netty.channel.pool.SimpleChannelPool");
|
||||
private final Deque<Channel> deque = PlatformDependent.newConcurrentDeque();
|
||||
private final ChannelPoolHandler handler;
|
||||
private final ChannelHealthChecker healthCheck;
|
||||
@ -172,7 +172,7 @@ public class SimpleChannelPool implements ChannelPool {
|
||||
if (ch == null) {
|
||||
// No Channel left in the pool bootstrap a new Channel
|
||||
Bootstrap bs = bootstrap.clone();
|
||||
bs.attr(poolKey, this);
|
||||
bs.attr(POOL_KEY, this);
|
||||
ChannelFuture f = connectChannel(bs);
|
||||
if (f.isDone()) {
|
||||
notifyConnect(f, promise);
|
||||
@ -238,7 +238,7 @@ public class SimpleChannelPool implements ChannelPool {
|
||||
if (future.isSuccess()) {
|
||||
if (future.getNow()) {
|
||||
try {
|
||||
ch.attr(poolKey).set(this);
|
||||
ch.attr(POOL_KEY).set(this);
|
||||
handler.channelAcquired(ch);
|
||||
promise.setSuccess(ch);
|
||||
} catch (Throwable cause) {
|
||||
@ -294,7 +294,7 @@ public class SimpleChannelPool implements ChannelPool {
|
||||
private void doReleaseChannel(Channel channel, Promise<Void> promise) {
|
||||
assert channel.eventLoop().inEventLoop();
|
||||
// Remove the POOL_KEY attribute from the Channel and check if it was acquired from this pool, if not fail.
|
||||
if (channel.attr(poolKey).getAndSet(null) != this) {
|
||||
if (channel.attr(POOL_KEY).getAndSet(null) != this) {
|
||||
closeAndFail(channel,
|
||||
// Better include a stacktrace here as this is an user error.
|
||||
new IllegalArgumentException(
|
||||
@ -359,7 +359,7 @@ public class SimpleChannelPool implements ChannelPool {
|
||||
}
|
||||
|
||||
private void closeChannel(Channel channel) {
|
||||
channel.attr(poolKey).getAndSet(null);
|
||||
channel.attr(POOL_KEY).getAndSet(null);
|
||||
channel.close();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user