Go 中 map 的底层结构和扩容机制

1. map 的底层结构

Go 中的 map 是基于哈希表实现的,其底层由两个核心结构体组成:hmapbmap

  • hmap:是 map 的头部结构,包含以下字段:

    • count:当前 map 中的键值对数量。

    • B:桶的数量指数,2^B 是当前桶的数量。

    • buckets:指向当前桶数组的指针。

    • oldbuckets:扩容时,指向旧桶数组的指针。

    • nevacuate:记录扩容进度。

    • extra:存储额外信息(如溢出桶等)。

  • bmap:是存储键值对的桶结构,每个桶最多存储 8 个键值对。桶内通过哈希值的高位和低位来定位键值对。

2. 扩容机制

map 中的元素数量增加时,为了维持高效的存取性能,map 会自动触发扩容操作。扩容机制的核心步骤如下:

2.1 触发扩容的条件
  1. 负载因子超过阈值:负载因子是指 map 中元素数量与桶数量的比值。当负载因子超过 6.5 时,会触发扩容。

  2. 溢出桶过多:当某个桶的溢出链表过长时,也会触发扩容。

2.2 扩容过程
  1. 创建新桶数组:新桶数组的大小通常是旧桶数组的两倍。

  2. 渐进式迁移:Go 采用渐进式扩容策略,即每次插入或删除操作时,会迁移部分桶中的数据。这种策略可以避免一次性迁移所有数据导致的性能抖动。

  3. 重新哈希:将旧桶中的键值对重新计算哈希值,并迁移到新桶中。

2.3 扩容的细节
  • 扩容时,旧桶中的键值对会根据新的哈希值重新分配到新桶中。

  • 如果某个键值对被删除,其对应的桶不会立即清理,而是标记为 emptyOne,以避免在扩容时重新插入。

  • 每次插入或删除操作时,都会调用 growWork 函数,逐步完成扩容。

3. 扩容的优化
  • 渐进式扩容:避免一次性迁移所有数据,减少性能抖动。

  • 负载因子:通过合理的负载因子(如 6.5),在性能和空间利用率之间取得平衡。

4. 注意事项
  • 线程安全:Go 的 map 不是线程安全的。在并发环境中,需要通过锁(如 sync.Mutex)来保证并发安全。

  • 内存布局:由于 map 可能会扩容,其键值对的内存地址可能会发生变化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yy_Yyyyy_zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值