Reduce the amount of memory used for handler names

- Fixes #1123
This commit is contained in:
Trustin Lee 2013-03-07 12:43:16 +09:00
parent 303f83043b
commit 148abe52f9

View File

@ -33,6 +33,7 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.WeakHashMap;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import static io.netty.channel.DefaultChannelHandlerContext.*; import static io.netty.channel.DefaultChannelHandlerContext.*;
@ -45,6 +46,17 @@ final class DefaultChannelPipeline implements ChannelPipeline {
static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelPipeline.class); static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelPipeline.class);
@SuppressWarnings("unchecked")
private static final WeakHashMap<Class<?>, String>[] nameCaches =
new WeakHashMap[Runtime.getRuntime().availableProcessors()];
static {
for (int i = 0; i < nameCaches.length; i ++) {
nameCaches[i] = new WeakHashMap<Class<?>, String>();
}
}
final Channel channel; final Channel channel;
final DefaultChannelHandlerContext head; final DefaultChannelHandlerContext head;
@ -350,14 +362,40 @@ final class DefaultChannelPipeline implements ChannelPipeline {
return this; return this;
} }
private static String generateName(ChannelHandler handler) { private String generateName(ChannelHandler handler) {
String type = handler.getClass().getSimpleName(); WeakHashMap<Class<?>, String> cache = nameCaches[(int) (Thread.currentThread().getId() % nameCaches.length)];
StringBuilder buf = new StringBuilder(type.length() + 10); Class<?> handlerType = handler.getClass();
buf.append(type); String name;
buf.append("-0"); synchronized (cache) {
buf.append(Long.toHexString(System.identityHashCode(handler) & 0xFFFFFFFFL | 0x100000000L)); name = cache.get(handlerType);
buf.setCharAt(buf.length() - 9, 'x'); if (name == null) {
return buf.toString(); Package pkg = handlerType.getPackage();
if (pkg != null) {
name = handlerType.getName().substring(pkg.getName().length() + 1);
} else {
name = handlerType.getName();
}
name += "#0";
cache.put(handlerType, name);
}
}
synchronized (this) {
// It's not very likely for a user to put more than one handler of the same type, but make sure to avoid
// any name conflicts. Note that we don't cache the names generated here.
if (name2ctx.containsKey(name)) {
String baseName = name.substring(0, name.length() - 1); // Strip the trailing '0'.
for (int i = 1;; i ++) {
String newName = baseName + i;
if (!name2ctx.containsKey(newName)) {
name = newName;
break;
}
}
}
}
return name;
} }
@Override @Override
@ -792,6 +830,11 @@ final class DefaultChannelPipeline implements ChannelPipeline {
} }
} }
@Override
public Iterator<Map.Entry<String, ChannelHandler>> iterator() {
return toMap().entrySet().iterator();
}
/** /**
* Returns the {@link String} representation of this pipeline. * Returns the {@link String} representation of this pipeline.
*/ */
@ -1312,9 +1355,4 @@ final class DefaultChannelPipeline implements ChannelPipeline {
unsafe.flush(promise); unsafe.flush(promise);
} }
} }
@Override
public Iterator<Map.Entry<String, ChannelHandler>> iterator() {
return toMap().entrySet().iterator();
}
} }