Simplified LocalAddress implementation - no more global reference map that causes memory leak

This commit is contained in:
Trustin Lee 2009-02-13 06:52:04 +00:00
parent 1b28c126c5
commit 395fcbbd29
5 changed files with 22 additions and 54 deletions

View File

@ -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());
}
}

View File

@ -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());

View File

@ -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);

View File

@ -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() {

View File

@ -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);