Simplified LocalAddress implementation - no more global reference map that causes memory leak
This commit is contained in:
parent
1b28c126c5
commit
395fcbbd29
@ -22,11 +22,6 @@
|
||||
package org.jboss.netty.channel.local;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.jboss.netty.channel.ChannelException;
|
||||
import org.jboss.netty.util.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author The Netty Project (netty-dev@lists.jboss.org)
|
||||
@ -35,54 +30,24 @@ import org.jboss.netty.util.ConcurrentHashMap;
|
||||
* @version $Rev$, $Date$
|
||||
*/
|
||||
public final class LocalAddress extends SocketAddress implements Comparable<LocalAddress> {
|
||||
|
||||
private static final long serialVersionUID = -3601961747680808645L;
|
||||
|
||||
// FIXME: Memory leak - use ConcurrentWeakValueHashMap
|
||||
private static final ConcurrentMap<String, LocalAddress> addresses =
|
||||
new ConcurrentHashMap<String, LocalAddress>();
|
||||
|
||||
private static final AtomicInteger nextEphemeralPort = new AtomicInteger();
|
||||
|
||||
public static LocalAddress getInstance(String id) {
|
||||
if (id == null) {
|
||||
throw new NullPointerException("id");
|
||||
}
|
||||
LocalAddress a = addresses.get(id);
|
||||
if (a == null) {
|
||||
a = new LocalAddress(id);
|
||||
LocalAddress oldA = addresses.putIfAbsent(id, a);
|
||||
if (oldA != null) {
|
||||
a = oldA;
|
||||
}
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public static LocalAddress newEphemeralInstance() {
|
||||
for (long i = (long) Integer.MAX_VALUE - Integer.MIN_VALUE; i >= 0; i --) {
|
||||
String id = "ephemeral-" +
|
||||
Integer.toHexString(nextEphemeralPort.incrementAndGet());
|
||||
LocalAddress a = new LocalAddress(id);
|
||||
if (addresses.putIfAbsent(id, a) == null) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
// Not likely to reach here but let's be a paranoid.
|
||||
throw new ChannelException("failed to allocate a local ephemeral port");
|
||||
}
|
||||
public static final String EPHEMERAL = "ephemeral";
|
||||
|
||||
private final String id;
|
||||
private final boolean ephemeral;
|
||||
|
||||
private LocalAddress(String id) {
|
||||
public LocalAddress(String id) {
|
||||
if (id == null) {
|
||||
throw new NullPointerException("id");
|
||||
}
|
||||
id = id.trim().toLowerCase();
|
||||
if (id.length() == 0) {
|
||||
throw new IllegalArgumentException("empty id");
|
||||
}
|
||||
this.id = id;
|
||||
|
||||
ephemeral = id.startsWith("ephemeral-");
|
||||
ephemeral = id.equals("ephemeral");
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
@ -95,7 +60,11 @@ public final class LocalAddress extends SocketAddress implements Comparable<Loca
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id.hashCode();
|
||||
if (ephemeral) {
|
||||
return System.identityHashCode(this);
|
||||
} else {
|
||||
return id.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -104,7 +73,11 @@ public final class LocalAddress extends SocketAddress implements Comparable<Loca
|
||||
return false;
|
||||
}
|
||||
|
||||
return getId().equals(((LocalAddress) o).getId());
|
||||
if (ephemeral) {
|
||||
return this == o;
|
||||
} else {
|
||||
return getId().equals(((LocalAddress) o).getId());
|
||||
}
|
||||
}
|
||||
|
||||
public int compareTo(LocalAddress o) {
|
||||
@ -115,9 +88,4 @@ public final class LocalAddress extends SocketAddress implements Comparable<Loca
|
||||
public String toString() {
|
||||
return "local:" + getId();
|
||||
}
|
||||
|
||||
// Just in case someone serializes this class ..
|
||||
private Object readResolve() {
|
||||
return getInstance(getId());
|
||||
}
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ final class LocalClientChannelSink extends AbstractChannelSink {
|
||||
serverChannel, serverChannel.getFactory(), pipeline, this, channel);
|
||||
channel.pairedChannel = acceptedChannel;
|
||||
|
||||
bind(channel, succeededFuture(channel), LocalAddress.newEphemeralInstance());
|
||||
bind(channel, succeededFuture(channel), new LocalAddress(LocalAddress.EPHEMERAL));
|
||||
channel.remoteAddress = serverChannel.getLocalAddress();
|
||||
fireChannelConnected(channel, serverChannel.getLocalAddress());
|
||||
|
||||
|
@ -48,7 +48,7 @@ public class LocalExample {
|
||||
ChannelFactory factory = new LocalServerChannelFactory();
|
||||
ServerBootstrap bootstrap = new ServerBootstrap(factory);
|
||||
EchoHandler handler = new EchoHandler();
|
||||
LocalAddress socketAddress = LocalAddress.getInstance("1");
|
||||
LocalAddress socketAddress = new LocalAddress("1");
|
||||
bootstrap.getPipeline().addLast("handler", handler);
|
||||
bootstrap.bind(socketAddress);
|
||||
|
||||
|
@ -45,7 +45,7 @@ public class LocalTransportRegister {
|
||||
ServerBootstrap serverBootstrap = new ServerBootstrap(factory);
|
||||
EchoHandler handler = new EchoHandler();
|
||||
serverBootstrap.getPipeline().addLast("handler", handler);
|
||||
serverChannel = serverBootstrap.bind(LocalAddress.getInstance("localAddress"));
|
||||
serverChannel = serverBootstrap.bind(new LocalAddress("localAddress"));
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
|
@ -62,7 +62,7 @@ public class NettySessionListener implements HttpSessionListener, ChannelHandler
|
||||
return pipeline;
|
||||
}
|
||||
});
|
||||
ChannelFuture future = bootstrap.connect(LocalAddress.getInstance("netty"));
|
||||
ChannelFuture future = bootstrap.connect(new LocalAddress("netty"));
|
||||
future.awaitUninterruptibly();
|
||||
final Channel ch = future.getChannel();
|
||||
session.setAttribute(CHANNEL_PROP, ch);
|
||||
|
Loading…
x
Reference in New Issue
Block a user