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.Map;
import java.util.NoSuchElementException;
import java.util.WeakHashMap;
import java.util.concurrent.Future;
import static io.netty.channel.DefaultChannelHandlerContext.*;
@ -45,6 +46,17 @@ final class DefaultChannelPipeline implements ChannelPipeline {
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 DefaultChannelHandlerContext head;
@ -350,14 +362,40 @@ final class DefaultChannelPipeline implements ChannelPipeline {
return this;
}
private static String generateName(ChannelHandler handler) {
String type = handler.getClass().getSimpleName();
StringBuilder buf = new StringBuilder(type.length() + 10);
buf.append(type);
buf.append("-0");
buf.append(Long.toHexString(System.identityHashCode(handler) & 0xFFFFFFFFL | 0x100000000L));
buf.setCharAt(buf.length() - 9, 'x');
return buf.toString();
private String generateName(ChannelHandler handler) {
WeakHashMap<Class<?>, String> cache = nameCaches[(int) (Thread.currentThread().getId() % nameCaches.length)];
Class<?> handlerType = handler.getClass();
String name;
synchronized (cache) {
name = cache.get(handlerType);
if (name == null) {
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
@ -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.
*/
@ -1312,9 +1355,4 @@ final class DefaultChannelPipeline implements ChannelPipeline {
unsafe.flush(promise);
}
}
@Override
public Iterator<Map.Entry<String, ChannelHandler>> iterator() {
return toMap().entrySet().iterator();
}
}