参考
【netty】AttributeKey、AttributeMap、Attribute
正文
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
AbstractChannel会继承DefaultAttributeMap,这是一个为每个bucket用sync进行同步的哈希map:
/**
* Default {@link AttributeMap} implementation which use simple synchronization per bucket to keep the memory overhead
* as low as possible.
*/
public class DefaultAttributeMap implements AttributeMap {
// Initialize lazily to reduce memory consumption; updated by AtomicReferenceFieldUpdater above.
@SuppressWarnings("UnusedDeclaration")
private volatile AtomicReferenceArray<DefaultAttribute<?>> attributes;
- DefaultAttributeMap 是什么?
用来存储属性的Map,线程安全。
- DefaultAttributeMap 的数据结构?
哈希表,其中哈希数组用AtomicReferenceArray实现,使用链表法解决哈希碰撞问题,利用在bucket级别的synchronized保障线程安全。
- 它如何节约内存?
核心宗旨是尽可能lazy地添加内存。阅读
attr(AttributeKey<T> key)
可知,它会:
1. 尝试初始化一个attributes
2. 如果已经有了attributes,就尝试插入链头
3. 发生碰撞,尝试插入bucket的链表内
如下文代码块所示。 - 为啥要自己重新设计一个map类?
作者提到"Not using ConcurrentHashMap due to high memory consumption.",显然,在大量连接数下,ConcurrentHashMap 显得非常吃内存,作者做出一定的抉择。
public <T> Attribute<T> attr(AttributeKey<T> key) {
if (key == null) {
throw new NullPointerException("key");
}
// 1. 尝试初始化一个attributes
AtomicReferenceArray<DefaultAttribute<?>> attributes = this.attributes;
if (attributes == null) {
// Not using ConcurrentHashMap due to high memory consumption.
attributes = new AtomicReferenceArray<DefaultAttribute<?>>(BUCKET_SIZE);
if (!updater.compareAndSet(this, null, attributes)) {
attributes = this.attributes;
}
}
// 尝试插入bucket头
int i = index(key);
DefaultAttribute<?> head = attributes.get(i);
if (head == null) {
// No head exists yet which means we may be able to add the attribute without synchronization and just
// use compare and set. At worst we need to fallback to synchronization and waste two allocations.
head = new DefaultAttribute();
DefaultAttribute<T> attr = new DefaultAttribute<T>(head, key);
head.next = attr;
attr.prev = head;
if (attributes.compareAndSet(i, null, head)) {
// we were able to add it so return the attr right away
return attr;
} else {
head = attributes.get(i);
}
}
// 发生碰撞,尝试插入bucket的链表内
synchronized (head) {
DefaultAttribute<?> curr = head;
for (;;) {
DefaultAttribute<?> next = curr.next;
if (next == null) {
DefaultAttribute<T> attr = new DefaultAttribute<T>(head, key);
curr.next = attr;
attr.prev = curr;
return attr;
}
if (next.key == key && !next.removed) {
return (Attribute<T>) next;
}
curr = next;
}
}
}
实验
我们试图检查两种Map的内存占用情况