map 长度_go语言map类型详解【1】

map的基本组成

(go版本为1.10.12,实现map的源代码在文件/src/runtime/hashmap.go中)

  1. go语言的map用hash实现,相应的一个map由hmap结构体管理;

2. go语言抽象了bucket,桶的概念,他相当于一个存放连续内存的容器;每个桶的头部是bmap,之后是8个key,再是8个value,最后是1个溢出指针;当一个bucket溢出时可以挂载额外的桶,overflow指向它;

3. 一个map含有多个桶;根据map中key的hash值,散射到不同的bucket中;

由结构可知,访问速度是O(1)。

可以参考下这图(链接在图片注释中):

295f80beffb51a19ef0263c10c53615b.png
https://ethantang.top/posts/go-map/

63456198f481d3eb83ffce9f590c0cc0.png
https://www.cnblogs.com/JoZSM/p/11784037.html

一些常量

f36a7d68c471864513d8519985b79349.png
一个bucket的最大容量为8

78011c51113248bac4fe0b4dc253e0d3.png
扩散因子

扩散因子:loadFactorNum / loadFactorDen = 6.5;

元素数量 >= (hash桶数量(2^hashmap.B) * 6.5 / 8) 时,触发扩容

ps:2^hashmap.B 为桶的数量,下面会说这个 B;

b85b2fa63d1867f41b9bee8e578e7814.png

tophash用来存储key的hash值的高八位,这些常数又用来表示tophash状态,下面会讨论;

关于map定义的源码

  1. 关于map的定义在hashmap文件中,如下图所示:

e17d63179b00974b7cf1d35ef97bfd1f.png

首先是hmap,作为一个map的头部,源码中可以看出它包含了所有应该有的。下图做了部分说明:

a8f9850f730caa99a8c17e28068e6aa5.png

2. bmap的定义十分简单又特别重要,它存储了一个名为 tophash 的uint8类型数组,数组长度为 bucketCnt,这是个常量,被赋值为8;tophash用来存储key哈希值的高八位;但是又要分情况,如果它的值小于minTopHash,就用来表示状态。

be3e0bb0187a380eb6c5341255862b86.png

特别注意:实际分配内存时会申请一个更大的内存空间A,A的前8字节为bmap,后面依次跟8个key、8个value、1个溢出指针,map的桶结构实际指的是内存空间A;

d4574a0d7139013708045f480cd5bdcb.png

参考:(这篇文章go版本和我的不一样,我的go版本更新)

Golang之map tophash详解​blog.csdn.net
58b86af87584c0e09e1fa77a8f970503.png
当tophash对应的K/V被使用时,存的是key的哈希值的高8位;当tophash对应的K/V未被使用时,存的是K/V对应位置的状态;下面是map源码中对tophash状态值的定义。

cdb1bb0b3d2c94b64fed0c848b6103b3.png
当tophash[i] < 4时,表示存的是状态;
当tophash[i] >= 4时,表示存的是哈希值;
那么问题来了,如果key的哈希值高8位小于minTopHash时,这时候怎么区分是存的状态还是哈希值?
源码中的解决方法是将计算得到的hash值做一个判断,当计算的哈希值小于minTopHash时,会直接在原有哈希值基础上加上minTopHash,确保哈希值一定大于minTopHash。

d13ccfc250eb705a4959b0fa930840b4.png

上述其他四种状态也有相应的作用:

088f2cf493132dab8521b32fe9005592.png

举上面链接中的例子:

b611feebbd55209fcbbf9944c60f5353.png
https://blog.csdn.net/fengshenyun/article/details/97296412

扩容迁移,要把旧桶1的元素迁到新桶,因为新桶长度增长了一倍,因此旧桶1元素可能被迁移到新桶的1或5。当元素迁移到了1时,把旧桶tophash置为evacuatedX;反之,迁移到了5时,tophash置为evacuatedY。要注意置的是旧桶的tophash。

3. mapextra,额外桶,包含三个元素

90481f380e722f8a380c4d644f9a621d.png

7261c0cd6994f4c55a78087860ca9476.png

hmap.extra.nextOverflow初始时指向内存A中的后段,即hash数组结尾的下一个桶,也即第1个预留的溢出桶。所以当hash冲突需要使用到新的溢出桶时,会优先使用上述预留的溢出桶,hmap.extra.nextOverflow依次往后偏移直到用完所有的溢出桶,才有可能会申请新的溢出桶空间。

a17324cd74632dbdfec82a51e4d6740d.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值