map作为全局变量赋值_Dig101 - Go之读懂map的底层设计

本文深入探讨Go语言中map的内部结构、哈希方式、扩容策略等关键特性,通过源码分析阐述其精妙设计,包括使用2的对数表示桶数、优化hash定位、桶的扩容和溢出桶管理等,旨在帮助读者更好地理解和使用map。
摘要由CSDN通过智能技术生成

725981ff64cd5478569457ad7a1a3e6e.png
文章首发:公众号 newbmiao
Dig101: dig more, simplified more and know more

在golang中,map是一个不可或缺的存在。

它作为哈希表,简单易用,既能自动处理哈希碰撞,又能自动扩容或重新内存整理,避免读写性能的下降。

这些都要归功于其内部实现的精妙。本文尝试去通过源码去分析一下其背后的故事。

我们不会过多在源码分析上展开,只结合代码示例对其背后设计实现上做些总结,希望可以简单明了一些。

希望看完后,会让你对 map 的理解有一些帮助。网上也有很多不错的源码分析,会附到文末,感兴趣的同学自行查看下。

(本文分析基于 Mac 平台上go1.14beta1版本。长文预警 ... )

我们先简单过下map实现hash表所用的数据结构,这样方便后边讨论。

文章目录

  • 0x01 map 的内部结构
  • 0x02 map 的 hash 方式
  • 0x03 map 的扩容方式
  • 0x04 map 的初始化
  • 0x05 map 的读取
  • 0x06 map 的赋值
  • 0x07 map 的删除
  • 0x08 map 的遍历

0x01 map的内部结构

f401a06d93d4e72ccfc8827afc5af58d.png

在这里我们先弄清楚map实现的整体结构

map本质是hash表(hmap),指向一堆桶(buckets)用来承接数据,每个桶(bmap)能存8组k/v。

当有数据读写时,会用key的hash找到对应的桶。

为加速hash定位桶,bmap里记录了tophash数组(hash的高8位)

hash表就会有哈希冲突的问题(不同key的hash值一样,即hash后都指向同一个桶),为此map使用桶后链一个溢出桶(overflow)链表来解决当桶8个单元都满了,但还有数据需要存入此桶的问题。

剩下noverflow,oldbuckets,nevacuate,oldoverflow 会用于扩容,暂时先不展开

具体对应的数据结构详细注释如下:

(虽然多,先大致过一遍,后边遇到会在提到)

// runtime/map.go
// A header for a Go map.
type hmap struct {
    
  //用于len(map)
  count     int
  //标志位
  // iterator     = 1 // 可能有遍历用buckets
  // oldIterator  = 2 // 可能有遍历用oldbuckets,用于扩容期间
  // hashWriting  = 4 // 标记写,用于并发读写检测
  // sameSizeGrow = 8 // 用于等大小buckets扩容,减少overflow桶
  flags     uint8

  // 代表可以最多容纳loadFactor * 2^B个元素(loadFactor=6.5)
  B         uint8
  // overflow桶的计数,当其接近1<<15 - 1时为近似值
  noverflow uint16
  // 随机的hash种子,每个map不一样,减少哈希碰撞的几率
  hash0     uint32

  // 当前桶,长度为(0-2^B)
  buckets    unsafe.Pointer
  // 如果存在扩容会有扩容前的桶
  oldbuckets unsafe.Pointer
  // 迁移数,标识小于其的buckets已迁移完毕
  nevacuate  uintptr

  // 额外记录overflow桶信息,不一定每个map都有
  extra *mapextra
}

// 额外记录overflow桶信息
type mapextra struct {
    
  overflow    *[]*bmap
  oldoverflow *[]*bmap

  // 指向下一个可用overflow桶
  nextOverflow *bmap
}

const(
  // 每个桶8个k/v单元
  BUCKETSIZE  = 8
  // k或v类型大小大于128转为指针存储
  MAXKEYSIZE  = 128
  MAXELEMSIZE = 128
)

// 桶结构 (字段会根据key和elem类型动态生成,见下边bmap)
type bmap struct {
    
  // 记录桶内8个单元的高8位hash值,或标记空桶状态,用于快速定位key
  // emptyRest      = 0 // 此单元为空,且更高索引的单元也为空
  // emptyOne       = 1 // 此单元为空
  // evacuatedX     =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值