netty 2.1 Channel内存优化的DefaultAttributeMap

参考

【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的内存占用情况

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值