go.map

文章详细介绍了Go语言中map的内存结构,包括基于哈希表的实现,每个桶(bmap)可存储8个k-v对以及溢出处理。查询过程涉及哈希函数和bucket遍历。此外,文章阐述了map的扩容原因和时刻,如装载因子超过阈值或溢出桶过多,以及两种扩容策略:等量和翻倍扩容。最后,提到了渐进式驱逐策略,在扩容期间逐步迁移旧桶数据至新桶。
摘要由CSDN通过智能技术生成

1.map内存模型与查询

1.1map内存模型

map的底层结构是一个hash表,对于碰撞使用拉链法实现,其中的数据结构如下所示

type hmap struct {

	count     int    //元素个数
	flags     uint8
	B         uint8  // bucket的对数--log_2 
	noverflow uint16 // 计算key的hash时会传入hash函数
  
	buckets    unsafe.Pointer // 指向大小为 2^B 的Buckets数组. 
	oldbuckets unsafe.Pointer // 扩容的时候,大小为oldbuckets的两倍
  ··
}

type bmap struct {
	 //代表了go里面一个hash桶,里面存的每一个key的tophash(前八位hash值)
	tophash [bucketCnt]uint8
	
}

在这里插入图片描述

1.每个桶是一个bmap struct,其中每个桶可以装载8个k-v值,overflow指向溢出桶,如果桶装满了就会指向下一个bmap

2.如果按照 将k-v放在一起存储,那在每一个 key/value 对之后都要额外 padding 7 个字节;而将所有的 key,value 分别绑定到一起,成为两个数组存储,则只需要在最后添加 padding。

1.2 map查询机制

1.查找某个键值:

  1. 首先,根据key的类型,调用对应的哈希函数计算出哈希值。
  2. 然后,根据哈希值的高位(高8位),找到对应的bucket。
  3. 接着,在bucket中查找对应的key。
  4. 最后,找到对应的key后,返回其value。

需要注意的是,由于哈希值有可能会发生碰撞,因此同一个bucket中可能会有多个key-value对,这时需要遍历bucket(包括溢出桶)中的所有元素,找到对应的key-value对。

2.插入修改:

map的插入和修改操作都是通过key来进行的。如果key已经存在于map中,那么它对应的value就会被替换成新的值。如果key不存在,那么它对应的key-value对就会被插入到map中。插入和修改操作的底层实现是一样的,都是通过哈希函数将key映射到对应的桶中,然后将key-value对插入到桶中。

3.Go语言中对map的遍历是无序的,遍历map的时候并不是固定从0号桶开始遍历的,而是每次都从一个随机的桶开始,并且从这个桶中随机的一个cell开始遍历。

2.map扩容机制

2.1扩容原因与扩容时刻

1.为什么要扩容:使用hash表的目的就是要快速的查到key值,但是随着map中添加的key越来越多,发生碰撞的概率越来越大,增删改查的效率也会降低,夸张来说可能从哈希表变成链表。

2.扩容时刻:判断是否有太多的溢出桶或者装载因子(一个公式,定义为6.5)—每个槽的key

造成大量溢出桶的原因:不停的增加元素,创建了很多bucket,但是没有到装载因子的临界值。后来有删除元素,减小元素的总数量,就会出现很多的溢出桶。

2.2扩容类型与具体方法

因为有以上两种需要扩容的原因,所以下面是两种扩容类型

  • 1.等量扩容:数据不多但是溢出桶太多了,主要是对数据进行整理。

具体方法:开辟一个新的bucket空间,将老bucket中元素放到新的bucket中,使得key排列更紧密。

  • 2.翻倍扩容:数据太多了

具体方法:将B+1,bucket直接变成两倍,就会存在新老bucket,但是此时元素都在老bucket中,并未迁移。对老桶中的一些设置进行更新(B,flag,oldbuckets,buckets等),更新extra结构体。

  h.B += bigger
	h.flags = flags
	h.oldbuckets = oldbuckets
	h.buckets = newbuckets
	h.nevacuate = 0
	h.noverflow = 0

2.3渐进式驱逐

渐进式驱逐(evacuate方法):每次操作一个旧桶的时候,将旧桶数据驱逐到新桶中,读取时不进行驱逐,只判断读取新桶还是旧桶。因此,在渐进式驱逐过程中,旧桶和新桶会共存一段时间,直到全部数据都被转移到新桶中为止,如果所有旧桶的数据迁移完成,回收旧桶。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

乔可南-

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

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

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

打赏作者

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

抵扣说明:

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

余额充值