โโโโโโโโโโโโโโโ
โ hmap โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ
โ count int โ โ โ โโโโโโโโโโโโโโโโโโโถโ bmap โ โโโโโถโ bmap โ
โ โ โ โผ โ โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ โ โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโฌโโโโโโ โ โ tophash [bucketCnt]uint8 โ โ โ tophash [bucketCnt]uint8 โ
โ flags uint8 โ โ โฒ โ 0 โ โ โ โ โ โ โ
โ โ โ โ โ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโค
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โ โโโโโโโค โ keys โ โ โ โ keys โ โ
โ B uint8 โ โ โ โ 1 โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค
โ โ โ โ โ โโโโโโโโโโโโโโโโโโโโ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โ โโโโโโโค โ โโโโโดโโโโดโโโฌโดโโโโดโโโโดโโโโดโโโโดโโโโค โ โโโโโดโโโโดโโโฌโดโโโโดโโโโดโโโโดโโโโดโโโโค
โ noverflow uint16 โ โ โ โ 2 โ โ โ values โ โ โ โ values โ โ
โ โ โ โ โ โ โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โ โโโโโโโค โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โ hash0 uint32 โ โ โ โ 3 โ โ โโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโค โ โโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโค
โ โ โ โ โ โ โ โ overflow *bmap โ โ โ overflow *bmap โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โ โโโโโโโค โ โ โโโโโโ โ โ
โ buckets unsafe.Pointer โ โ โ โ 4 โ โ โโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โโโโโโโโโโโโโ โ โ โ โโโโโโโโโโโโโโโโโโโถโ bmap โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โโโโโโโค โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ
โ oldbuckets unsafe.Pointer โ โ 5 โ โ tophash [bucketCnt]uint8 โ
โ โ โ โ โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค size = 2 ^ B โโโโโโโค โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโค
โ nevacuate uintptr โ โ 6 โ โ keys โ โ
โ โ โ โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโค โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โ extra *mapextra โ โ โ 7 โ โโโโโดโโโโดโโโฌโดโโโโดโโโโดโโโโดโโโโดโโโโค
โโโโ โ โ โ โ โ values โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โโโโโโโ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค
โ โ .... โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โ โ โโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโค
โ โ โโโโโโโ โ overflow *bmap โ
โ โ โ 61 โ โ โ
โ โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โผ โ โโโโโโโค ............
โโโโโโโโโโโโโโโ โ โ 62 โ โโโโโโโโโโโ โโโโโโโโโโโ โโโโโโโโโโโ
โ mapextra โ โ โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถโ bmap โ โโโโโถโ bmap โ โโโโโถโ bmap โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโ โ โโโโโโโค โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ โ โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ โ โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ
โ overflow *[]*bmap โ โ โ 63 โ โ tophash [bucketCnt]uint8 โ โ โ tophash [bucketCnt]uint8 โ โ โ tophash [bucketCnt]uint8 โ
โ โ โผ โ โโโโโโโโโโโโโโโโโโโโ โ โ โ โ โ โ โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โโโโโโโโโดโโโโโโ โ โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโค โ โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโค
โ oldoverflow *[]*bmap โ โ โ keys โ โ โ โ keys โ โ โ โ keys โ โ
โ โ โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โ nextoverflow *bmap โ โ โโโโโดโโโโดโโโฌโดโโโโดโโโโดโโโโดโโโโดโโโโค โ โโโโโดโโโโดโโโฌโดโโโโดโโโโดโโโโดโโโโดโโโโค โ โโโโโดโโโโดโโโฌโดโโโโดโโโโดโโโโดโโโโดโโโโค
โ โ โ โ values โ โ โ โ values โ โ โ โ values โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค โ โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค
โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โ โโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโค โ โโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโค โ โโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโค
โ โ overflow *bmap โ โ โ overflow *bmap โ โ โ overflow *bmap โ
โ โ โโโโโโ โ โโโโโ โ โ
โ โโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโถโ bmap โ
โโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโ
โ tophash [bucketCnt]uint8 โ
โ โ
โโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโค
โ keys โ โ
โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค
โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โโโโโดโโโโดโโโฌโดโโโโดโโโโดโโโโดโโโโดโโโโค
โ values โ โ
โโโโโฌโโโโฌโโโดโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโค
โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโค
โ overflow *bmap โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const (
// ไธไธช bucket ๆๅค่ฝๆพ็ๅ
็ด ๆฐ
bucketCntBits = 3
bucketCnt = 1 << bucketCntBits
// load factor = 13/2
loadFactorNum = 13
loadFactorDen = 2
// ่ถ
่ฟ่ฟไธคไธช size ็ๅฏนๅบๅฏน่ฑก๏ผไผ่ขซ่ฝฌไธบๆ้
maxKeySize = 128
maxValueSize = 128
// data offset should be the size of the bmap struct, but needs to be
// aligned correctly. For amd64p32 this means 64-bit alignment
// even though pointers are 32 bit.
dataOffset = unsafe.Offsetof(struct {
b bmap
v int64
}{}.v)
// tophash ้คไบๆพๆญฃๅธธ็้ซ 8 ไฝ็ hash ๅผ
// ่ฟไผๅจ็ฉบ้ฒใ่ฟ็งปๆถๅญๅจไธไบ็นๅพ็็ถๆๅผ
// ๆไปฅๅๆณ็ tophash(ๆ่ฎก็ฎๅบๆฅ็้ฃ็ง)๏ผๆๅฐไนๅบ่ฏฅๆฏ 4
// ๅฐไบ 4 ็่กจ็คบ็้ฝๆฏๆไปฌ่ชๅทฑๅฎไน็็ถๆๅผ
empty = 0 // cell is empty
evacuatedEmpty = 1 // cell is empty, bucket is evacuated.
evacuatedX = 2 // key/value is valid. Entry has been evacuated to first half of larger table.
evacuatedY = 3 // same as above, but evacuated to second half of larger table.
minTopHash = 4 // minimum tophash for a normal filled cell.
// flags
iterator = 1 // there may be an iterator using buckets
oldIterator = 2 // there may be an iterator using oldbuckets
hashWriting = 4 // a goroutine is writing to the map
sameSizeGrow = 8 // the current map growth is to a new map of the same size
// sentinel bucket ID for iterator checks
noCheck = 1<<(8*sys.PtrSize) - 1
)
// A header for a Go map.
type hmap struct {
count int // map ไธญ็ๅ
็ด ไธชๆฐ๏ผๅฟ
้กปๆพๅจ struct ็็ฌฌไธไธชไฝ็ฝฎ๏ผๅ ไธบ ๅ
็ฝฎ็ len ๅฝๆฐไผไป่ฟ้่ฏปๅ
flags uint8
B uint8 // log_2 of # of buckets (ๆๅคๅฏไปฅๆพ loadFactor * 2^B ไธชๅ
็ด ๏ผๅๅคๅฐฑ่ฆ hashGrow ไบ)
noverflow uint16 // overflow ็ bucket ็่ฟไผผๆฐ
hash0 uint32 // hash seed
buckets unsafe.Pointer // 2^B ๅคงๅฐ็ๆฐ็ป๏ผๅฆๆ count == 0 ็่ฏ๏ผๅฏ่ฝๆฏ nil
oldbuckets unsafe.Pointer // ไธๅๅคงๅฐ็ไนๅ็ bucket ๆฐ็ป๏ผๅชๆๅจ growing ่ฟ็จไธญๆฏ้ nil
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // ๅฝ key ๅ value ้ฝๅฏไปฅ inline ็ๆถๅ๏ผๅฐฑไผ็จ่ฟไธชๅญๆฎต
}
type mapextra struct {
// ๅฆๆ key ๅ value ้ฝไธๅ
ๅซๆ้๏ผๅนถไธๅฏไปฅ่ขซ inline(<=128 ๅญ่)
// ไฝฟ็จ extra ๆฅๅญๅจ overflow bucket๏ผ่ฟๆ ทๅฏไปฅ้ฟๅ
GC ๆซๆๆดไธช map
// ็ถ่ bmap.overflow ไนๆฏไธชๆ้ใ่ฟๆถๅๆไปฌๅช่ฝๆ่ฟไบ overflow ็ๆ้
// ้ฝๆพๅจ hmap.extra.overflow ๅ hmap.extra.oldoverflow ไธญไบ
// overflow ๅ
ๅซ็ๆฏ hmap.buckets ็ overflow ็ bucket
// oldoverflow ๅ
ๅซๆฉๅฎนๆถ็ hmap.oldbuckets ็ overflow ็ bucket
overflow *[]*bmap
oldoverflow *[]*bmap
// ๆๅ็ฉบ้ฒ็ overflow bucket ็ๆ้
nextOverflow *bmap
}
// bucket ๆฌไฝ
type bmap struct {
// tophash ๆฏ hash ๅผ็้ซ 8 ไฝ
tophash [bucketCnt]uint8
// keys
// values
// overflow pointer
}
ๅฝขๅฆ:
make(map[k]v, hint)
็ไปฃ็ ๏ผๅจ hint <= 8(bucketSize) ๆถ๏ผไผ่ฐ็จ makemap_small ๆฅ่ฟ่กๅๅงๅ๏ผๅฆๆ hint > 8๏ผๅ่ฐ็จ makemapใ
make(map[k]v) // ๆต่ฏๆถ๏ผๆ่ฟไธชไฝไธบไธไธชๅ
จๅฑๅ้ var a = make(map[int]int)
ไธๆไพ hint ็ไปฃ็ ๏ผ็ผ่ฏๅจๅง็ปไผ่ฐ็จ makemap_small ๆฅๅๅงๅใ
// make(map[k]v, hint)
// ๅฆๆ็ผ่ฏๅจ่ฎคไธบ map ๅ็ฌฌไธไธช bucket ๅฏไปฅ็ดๆฅๅๅปบๅจๆ ไธ๏ผh ๅ bucket ๅฏ่ฝ้ฝๆฏ้็ฉบ
// h != nil๏ผๅฏไปฅ็ดๆฅๅจ h ๅ
ๅๅปบ map
// ๅฆๆ h.buckets != nil๏ผๅ
ถๆๅ็ bucket ๅฏไปฅไฝไธบ็ฌฌไธไธช bucket ๆฅไฝฟ็จ
func makemap(t *maptype, hint int, h *hmap) *hmap {
// ๅจ 64 ไฝ็ณป็ปไธ hmap ็ปๆไฝๅคงๅฐไธบ 48 ๅญ่
// 32 ไฝ็ณป็ปไธๆฏ 28 ๅญ่
if sz := unsafe.Sizeof(hmap{}); sz != 8+5*sys.PtrSize {
println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size)
throw("bad hmap size")
}
if hint < 0 || hint > int(maxSliceCap(t.bucket.size)) {
hint = 0
}
// ๅๅงๅ hmap
if h == nil {
h = (*hmap)(newobject(t.hmap))
}
h.hash0 = fastrand()
// ๆ็
งๆไพ็ๅ
็ด ไธชๆฐ๏ผๆพไธไธชๅฏไปฅๆพๅพไธ่ฟไนๅคๅ
็ด ็ B ๅผ
B := uint8(0)
for overLoadFactor(hint, B) {
B++
}
h.B = B
// ๅ้
ๅๅง็ hash table
// ๅฆๆ B == 0๏ผbuckets ๅญๆฎตไผ็ฑ mapassign ๆฅ lazily ๅ้
// ๅ ไธบๅฆๆ hint ๅพๅคง็่ฏ๏ผๅฏน่ฟ้จๅๅ
ๅญๅฝ้ถไผ่ฑๆฏ่พ้ฟๆถ้ด
if h.B != 0 {
var nextOverflow *bmap
h.buckets, nextOverflow = makeBucketArray(t, h.B)
if nextOverflow != nil {
h.extra = new(mapextra)
h.extra.nextOverflow = nextOverflow
}
}
return h
}
ๅฝ็ถ๏ผๅฎ้ ้็จๅชไธชๅฝๆฐไธๅช่ฆ็ hint๏ผ่ฟ่ฆ็้้ธๅๆ็ปๆ๏ผๆฏๅฆไธ้ข่ฟๆฎตไปฃ็ ๏ผๅจ็ๆ็ๆฑ็ผไธญ๏ผไฝ ๆฏๆพไธๅฐ makemap ็่ธชๅฝฑ็๏ผ
package main
func main() {
var m = make(map[int]int, 4)
m[1] = 1
}
็ผ่ฏๅจ็กฎๅฎ make map ๅฝๆฐ็ไฝ็ฝฎๅจ๏ผcmd/compile/internal/gc/walk.go:1192:
case OMAKEMAP:
t := n.Type
hmapType := hmap(t)
hint := n.Left
ๆๅ ด่ถฃ็ๅๅญฆๅฏไปฅ่ช่กๆฅ็~
ไธป่ฆๆฏๅฏน key ่ฟ่ก hash ่ฎก็ฎ๏ผ่ฎก็ฎๅ็จ low bits ๅ้ซ 8 ไฝ hash ๆพๅฐๅฏนๅบ็ไฝ็ฝฎ:
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ 10010111 โ 000011110110110010001111001010100010010110010101010 โ 01010 โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโ
โฒ โฒ
โ โ
โ โ B = 5
โ โ bucketMask = 11111
โ โ
โ โโโโโโโโโโโโโโโฌโโโโฌโโโโโโโโโโโโโโ
โ โ low bits โ & โ bucketMask โ
โ โโโโโโโโโโโโโโโดโโโโดโโโโโโโโโโโโโโค
โ โ 01010 & 11111 โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ โ
โ โ
โ โผ
โ โโโโโโโโโโโโโโโโโโโโโ
โ โ 01010 = 12 โ
โ โโโโโโโโโโโโโโโโโโโโโ
โ โ
โ โ
โ โ
โ โ
โ โ
โโโโโโโโโโโโโโโ โ
โ tophash โ โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโ โ
โ โ buckets โ โผ
โ โโโโโฌโโโโฌโโดโโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโฌโโโโ โโโโโฌโโโโฌโโโโ
โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ 8 โ 9 โ10 โ11 โ ...โ29 โ30 โ31 โ
โ โโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโดโโโโ โโโโโดโโโโดโโโโ
โผ โ
โโโโโโโโโโโโโโโโโโโโ โ
โ 10010111 = 151 โโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโ โ โ
โ โ
โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
โ โ
โ โ
โ โ
โ โ
โ โ
โ โผ
โ โโโโโโโโโโโโโโโ
โ โ bucket โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโค
โ โ โ
โ โโโโโโโโโโโ โ โ
โ โ tophash โ โผ โ
โ โโโโโโโโโฌโโดโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโโ
โ โ 124 โ 33 โ 41 โ 151 โ 1 โ 0 โ 0 โ 0 โโ
โ โโโโโโโโโดโโฌโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโโ
โ โ 1 โ โ
โ โโโโโโโโโฌโโดโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโโ
โ โ 124 โ 412 โ 423 โ 5 โ 14 โ 0 โ 0 โ 0 โโ
โ โโโโโโโโโดโโฌโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโโ
โ โ values โ โ
โ โโโโโโโโโฌโโดโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโฌโโโโโโโโโ
โ โ v0 โ v1 โ v2 โ v3 โ v4 โ 0 โ 0 โ 0 โโ
โ โโโโโโโโโดโโโโโโโโดโโโฌโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโดโโโโโโโโโ
โ โ overflow pointer โ โ
โ โโโโโโโโโโโโโโโโโโโโ โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ๅฎ็ฐไธๆ mapaccess1๏ผmapaccess2๏ผmapaccessK ๅ ไธชๆนๆณ๏ผไฝๅ ไธชๆนๆณ้ฝๅทฎไธๅค๏ผๅชๅทฎๅซๅจ่ฟๅๅ ๅฎนไธใmapaccess1 ๅ mapaccess2 ๅๆถๆ 32 ไฝใ64 ไฝๅ string ็ฑปๅ็ๅ็ง:
- mapaccess1_fast32, mapaccess1_fast64, mapaccess1_faststr
- mapaccess2_fast32, mapaccess2_fast64, mapaccess2_faststr
ๅ ทไฝ็จๅชไธไธชๅ็งๅฝๆฐๆฏ็ฑ็ผ่ฏๅจๅจ็ผ่ฏๆ้ๆฉ็๏ผ้ๆฉไพๆฎๅฏไปฅๅ่ๅ้ข็่ตๅผไธๅฐ่ใ
ๅ ไธบ่ฟไบๅฝๆฐๅฎ็ฐไธ้ฝๅคงๅๅฐๅผ๏ผๆไปฌๆไธไธชๆฅ็็ mapaccess2:
func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) {
// map ไธบ็ฉบ๏ผๆ่
ๅ
็ด ๆฐไธบ 0๏ผ็ดๆฅ่ฟๅๆชๆพๅฐ
if h == nil || h.count == 0 {
return unsafe.Pointer(&zeroVal[0]), false
}
if h.flags&hashWriting != 0 {
throw("concurrent map read and map write")
}
alg := t.key.alg
// ไธๅ็ฑปๅ็ key๏ผๆ็จ็ hash ็ฎๆณๆฏไธไธๆ ท็
// ๅ
ทไฝๅฏไปฅๅ่ algarray
hash := alg.hash(key, uintptr(h.hash0))
// ๅฆๆ B = 3๏ผ้ฃไน็ปๆ็จไบ่ฟๅถ่กจ็คบๅฐฑๆฏ 111
// ๅฆๆ B = 4๏ผ้ฃไน็ปๆ็จไบ่ฟๅถ่กจ็คบๅฐฑๆฏ 1111
m := bucketMask(h.B)
// ๆไฝ &๏ผๅฏไปฅ select ๅบๅฏนๅบ็ bucket
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
// ไผ็จๅฐ h.oldbuckets ๆถ๏ผ่ฏดๆ map ๅ็ไบๆฉๅฎน
// ่ฟๆถๅ๏ผๆฐ็ buckets ้ๅฏ่ฝ่ฟๆฒกๆ่็ๅ
ๅฎน
// ๆไปฅไธๅฎ่ฆๅจ่็้้ขๆพ๏ผๅฆๅๆๅฏ่ฝๅ็โๆถๅคฑโ็่ฏกๅผ็ฐ่ฑก
if c := h.oldbuckets; c != nil {
if !h.sameSizeGrow() {
// ่ฏดๆไนๅๅชๆไธๅ็ bucket๏ผ้่ฆ้ค 2
m >>= 1
}
oldb := (*bmap)(unsafe.Pointer(uintptr(c) + (hash&m)*uintptr(t.bucketsize)))
if !evacuated(oldb) {
b = oldb
}
}
// tophash ๅๅ
ถ้ซ 8bit ็ๅผ
top := tophash(hash)
for ; b != nil; b = b.overflow(t) {
// ไธไธช bucket ๅจๅญๅจๆปก 8 ไธชๅ
็ด ๅ๏ผๅฐฑๅไนๆพไธไธไบ
// ่ฟๆถๅไผๅๅปบๆฐ็ bucket
// ๆๅจๅๆฅ็ bucket ็ overflow ๆ้ๆๅไธ
for i := uintptr(0); i < bucketCnt; i++ {
// ๅพช็ฏๅฏนๆฏ bucket ไธญ็ tophash ๆฐ็ป
// ๅฆๆๆพๅฐไบ็ธ็ญ็ tophash๏ผ้ฃ่ฏดๆๅฐฑๆฏ่ฟไธช bucket ไบ
if b.tophash[i] != top {
continue
}
k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
if t.indirectkey {
k = *((*unsafe.Pointer)(k))
}
if alg.equal(key, k) {
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
if t.indirectvalue {
v = *((*unsafe.Pointer)(v))
}
return v, true
}
}
}
// ๆๆ bucket ้ฝๆฒกๆๆพๅฐ๏ผ่ฟๅ้ถๅผๅ false
return unsafe.Pointer(&zeroVal[0]), false
}
ๆพ็ถ๏ผ่ฟๅฐฑๆฏๆไปฌๅนณๅธธๅจๅๅฆไธไปฃ็ ๆถ:
v, ok := m[k]
ๆไฝฟ็จ็ๅบๅฑๅฝๆฐใ
mapassign ๆๅ ไธชๅ็ง๏ผๆฏ็ฑ็ผ่ฏๅจๅณๅฎๅ ทไฝ็จๅชไธไธชๅฝๆฐ็ใ้ๆฉไพๆฎ:
- key ็็ฑปๅๆฏๅฆๆฏ string
- ๅฆๆไธๆฏ string๏ผ้ฃไนๆ นๆฎ key ็็ฑปๅๅคงๅฐๅ้ๆฉ
ๆต็จๅพ:
graph TD
Z[value size gte 128] --> |yes|G[mapassign]
Z --> |no| A[key is string]
A --> |yes|B[mapassign_faststr]
A --> |no|C[key size is 32]
C --> |yes|D[mapassign_fast32]
C --> |no|E[key size is 64]
E --> |yes|F[mapassign_fast64]
E --> |no|G[mapassign]
ๅ ไธชๅฝๆฐ้ฟๅพ้ฝๅทฎไธๅค๏ผๆไปฌ็ไธไธ mapassign ็้ป่พๅฐฑ่กไบ:
// ๅ mapaccess ๅฝๆฐๅทฎไธๅค๏ผไฝๅจๆฒกๆๆพๅฐ key ๆถ๏ผไผไธบ key ๅ้
ไธไธชๆฐ็ๆงฝไฝ
func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
if h == nil {
// nil map ไธ่ฝ่ฟ่ก่ตๅผๆไฝ
panic(plainError("assignment to entry in nil map"))
}
if h.flags&hashWriting != 0 {
throw("concurrent map writes")
}
// ่ฐ็จๅฏนๅบ็ฑปๅ็ hash ็ฎๆณ
alg := t.key.alg
hash := alg.hash(key, uintptr(h.hash0))
// ่ฐ็จ alg.hash ่ฎพ็ฝฎ hashWriting ็ flag๏ผๅ ไธบ alg.hash ๅฏ่ฝไผ panic
// ่ฟๆถๅๆไปฌๆฒกๆณๅฎๆไธๆฌกๅๆไฝ
h.flags |= hashWriting
if h.buckets == nil {
// ๅ้
็ฌฌไธไธช buckt
h.buckets = newobject(t.bucket) // newarray(t.bucket, 1)
}
again:
// ่ฎก็ฎไฝ 8 ไฝ hash๏ผๆ นๆฎ่ฎก็ฎๅบ็ bucketMask ้ๆฉๅฏนๅบ็ bucket
// mask : 1111111
bucket := hash & bucketMask(h.B)
if h.growing() {
growWork(t, h, bucket)
}
// ่ฎก็ฎๅบๅญๅจ็ bucket ็ๅ
ๅญไฝ็ฝฎ
// pos = start + bucketNumber * bucetsize
// ่ฟ้็ๅฝๅไธๅคชๅฅฝ๏ผbucket ๅ
ถๅฎๆฏ bucketNumber
b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + bucket*uintptr(t.bucketsize)))
// ่ฎก็ฎ้ซ 8 ไฝ hash
top := tophash(hash)
var inserti *uint8
var insertk unsafe.Pointer
var val unsafe.Pointer
for {
for i := uintptr(0); i < bucketCnt; i++ {
// ้ๅ 8 ไธช bucket ไธญ็ๅ
็ด
// ่ฟ้็ bucketCnt ๆฏๅ
จๅฑๅธธ้
// ๅ
ถๅฎๅซ bucketElemCnt ๆดๅ้
if b.tophash[i] != top {
// ๅจ b.tophash[i] != top ็ๆ
ๅตไธ
// ็่ฎบไธๆๅฏ่ฝไผๆฏไธไธช็ฉบๆงฝไฝ
// ไธ่ฌๆ
ๅตไธ map ็ๆงฝไฝๅๅธๆฏ่ฟๆ ท็๏ผe ่กจ็คบ empty:
// [h1][h2][h3][h4][h5][e][e][e]
// ไฝๅจๆง่ก่ฟ delete ๆไฝๆถ๏ผๅฏ่ฝไผๅๆ่ฟๆ ท:
// [h1][h2][e][e][h5][e][e][e]
// ๆไปฅๅฆๆๅๆๅ
ฅ็่ฏ๏ผไผๅฐฝ้ๅพๅ้ข็ไฝ็ฝฎๆ
// [h1][h2][e][e][h5][e][e][e]
// ^
// ^
// ่ฟไธชไฝ็ฝฎ
// ๆไปฅๅจๅพช็ฏ็ๆถๅ่ฟ่ฆ้กบไพฟๆๅ้ข็็ฉบไฝ็ฝฎๅ
่ฎฐไธๆฅ
if b.tophash[i] == empty && inserti == nil {
// ๅฆๆ่ฟไธชๆงฝไฝๆฒกๆ่ขซๅ ๏ผ่ฏดๆๅฏไปฅๅพ่ฟ้ๅก key ๅ value
inserti = &b.tophash[i] // tophash ็ๆๅ
ฅไฝ็ฝฎ
insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
}
continue
}
k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
if t.indirectkey {
k = *((*unsafe.Pointer)(k))
}
// ๅฆๆ็ธๅ็ hash ไฝ็ฝฎ็ key ๅ่ฆๆๅ
ฅ็ key ๅญ้ขไธไธ็ธ็ญ
// ๅฆๆไธคไธช key ็้ฆๅ
ซไฝๅๆๅๅ
ซไฝๅๅธๅผไธๆ ท๏ผๅฐฑไผ่ฟ่กๅ
ถๅผๆฏ่พ
// ็ฎๆฏไธ็งๅๅธ็ขฐๆๅง
if !alg.equal(key, k) {
continue
}
// ๅฏนๅบ็ไฝ็ฝฎๅทฒ็ปๆ key ไบ๏ผ็ดๆฅๆดๆฐๅฐฑ่ก
if t.needkeyupdate {
typedmemmove(t.key, k, key)
}
val = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
goto done
}
// bucket ็ 8 ไธชๆงฝๆฒกๆๆปก่ถณๆกไปถ็่ฝๆๅ
ฅๆ่
่ฝๆดๆฐ็๏ผๅป overflow ้็ปง็ปญๆพ
ovf := b.overflow(t)
// ๅฆๆ overflow ไธบ nil๏ผ่ฏดๆๅฐไบ overflow ้พ่กจ็ๆซ็ซฏไบ
if ovf == nil {
break
}
// ่ตๅผไธบ้พ่กจ็ไธไธไธชๅ
็ด ๏ผ็ปง็ปญๅพช็ฏ
b = ovf
}
// ๆฒกๆๆพๅฐ key๏ผๅ้
ๆฐ็็ฉบ้ด
// ๅฆๆ่งฆๅไบๆๅคง็ load factor๏ผๆ่
ๅทฒ็ปๆๅคชๅค overflow buckets
// ๅนถไธ่ฟไธชๆถๅปๆฒกๆๅจ่ฟ่ก growing ็้ไธญ๏ผ้ฃไนๅฐฑๅผๅง growing
if !h.growing() && (overLoadFactor(h.count+1, h.B) || tooManyOverflowBuckets(h.noverflow, h.B)) {
hashGrow(t, h)
// hashGrow ็ๆถๅไผๆๅฝๅ็ bucket ๆพๅฐ oldbucket ้
// ไฝ่ฟๆฒกๆๅผๅงๅ้
ๆฐ็ bucket๏ผๆไปฅ้่ฆๅฐ again ้่ฏไธๆฌก
// ้่ฏ็ๆถๅๅจ growWork ้ไผๆ่ฟไธช key ็ bucket ไผๅ
ๅ้
ๅฅฝ
goto again // Growing the table invalidates everything, so try again
}
if inserti == nil {
// ๅ้ขๅจๆกถ้ๆพ็ๆถๅ๏ผๆฒกๆๆพๅฐ่ฝๅก่ฟไธช tophash ็ไฝ็ฝฎ
// ่ฏดๆๅฝๅๆๆ buckets ้ฝๆฏๆปก็๏ผๅ้
ไธไธชๆฐ็ bucket
newb := h.newoverflow(t, b)
inserti = &newb.tophash[0]
insertk = add(unsafe.Pointer(newb), dataOffset)
val = add(insertk, bucketCnt*uintptr(t.keysize))
}
// ๆๆฐ็ key ๅ value ๅญๅจๅฐๅบๆๅ
ฅ็ไฝ็ฝฎ
if t.indirectkey {
kmem := newobject(t.key)
*(*unsafe.Pointer)(insertk) = kmem
insertk = kmem
}
if t.indirectvalue {
vmem := newobject(t.elem)
*(*unsafe.Pointer)(val) = vmem
}
typedmemmove(t.key, insertk, key)
*inserti = top
h.count++
done:
if h.flags&hashWriting == 0 {
throw("concurrent map writes")
}
h.flags &^= hashWriting
if t.indirectvalue {
val = *((*unsafe.Pointer)(val))
}
return val
}
่ฟ้ๆไปถๆฏ่พๅฅๆช็ไบๆ
๏ผmapassign ๅนถๆฒกๆๆ็จๆท m[k] = v
ๆถ็ v ๅๅ
ฅๅฐ map ็ value ๅบๅ๏ผ่ๆฏ็ดๆฅ่ฟๅไบ่ฟไธชๅผๆๅบ่ฏฅๅจ็ๅ
ๅญๅฐๅใ้ฃไนๆ v ๆท่ดๅฐ่ฏฅๅ
ๅญๅบๅ็ๆไฝๆฏๅจๅช้ๅ็ๅข๏ผ
var a = make(map[int]int, 7)
for i := 0; i < 1000; i++ {
a[i] = 99999
}
็็็ๆ็ๆฑ็ผ้จๅ:
0x003f 00063 (m.go:9) MOVQ DX, (SP) // ็ฌฌไธไธชๅๆฐ
0x0043 00067 (m.go:9) MOVQ AX, 8(SP) // ็ฌฌไบไธชๅๆฐ
0x0048 00072 (m.go:9) MOVQ CX, 16(SP) // ็ฌฌไธไธชๅๆฐ
0x004d 00077 (m.go:9) PCDATA $0, $1 // GC ็ธๅ
ณ
0x004d 00077 (m.go:9) CALL runtime.mapassign_fast64(SB) // ่ฐ็จๅฝๆฐ
0x0052 00082 (m.go:9) MOVQ 24(SP), AX // ่ฟๅๅผ๏ผๅณ value ๅบ่ฏฅๅญๆพ็ๅ
ๅญๅฐๅ
0x0057 00087 (m.go:9) MOVQ $99999, (AX) // ๆ 99999 ๆพๅ
ฅ่ฏฅๅฐๅไธญ
่ตๅผ็ๆๅไธๆญฅๅฎ้ ไธๆฏ็ผ่ฏๅจ้ขๅค็ๆ็ๆฑ็ผๆไปคๆฅๅฎๆ็๏ผๅฏ่ง้ runtime ๆไบๅทฅไฝๆฏๆฒกๆๅๅฎ็ใ่ฟ้ๅ go ๅจๅฝๆฐ่ฐ็จๆถๆๅ ฅ prologue ๅ epilogue ๆฏ็ฑปไผผ็ใ็ผ่ฏๅจๅ runtime ้ ๅ๏ผๆ่ฝๅฎๆไธไบๅคๆ็ๅทฅไฝใ
func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
if h == nil || h.count == 0 {
return
}
if h.flags&hashWriting != 0 {
throw("concurrent map writes")
}
alg := t.key.alg
hash := alg.hash(key, uintptr(h.hash0))
// ่ฐ็จ alg.hash ่ฎพ็ฝฎ hashWriting ็ flag๏ผๅ ไธบ alg.hash ๅฏ่ฝไผ panic
// ่ฟๆถๅๆไปฌๆฒกๆณๅฎๆไธๆฌกๅๆไฝ
h.flags |= hashWriting
// ๆไฝ 8 ไฝ hash ๅผ้ๆฉ bucket
bucket := hash & bucketMask(h.B)
if h.growing() {
growWork(t, h, bucket)
}
// ๆไธ้ข็ฎๅบ็ๆกถ็็ดขๅผ๏ผๆพๅฐ bucket ็ๅ
ๅญๅฐๅ
// ๅนถๅผบๅถ่ฝฌๆขไธบ้่ฆ็ bmap ็ปๆ
b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize)))
// ้ซ 8 ไฝ hash ๅผ
top := tophash(hash)
search:
for ; b != nil; b = b.overflow(t) {
for i := uintptr(0); i < bucketCnt; i++ {
// ๅไธ้ข็ๅทฎไธๅค๏ผ8 ไธชๆงฝไฝ๏ผๅๅซๅฏนๆฏ tophash
// ๆฒกๆพๅฐ็่ฏๅฐฑๅปๅคๅด for ๅพช็ฏ็ overflow ้พ่กจไธญ็ปง็ปญๆฅๆพ
if b.tophash[i] != top {
continue
}
// b.tophash[i] == top
// ่ฎก็ฎ k ๆๅจ็ๆงฝไฝ็ๅ
ๅญๅฐๅ
k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize))
k2 := k
// ๅฆๆ key > 128 ๅญ่
if t.indirectkey {
k2 = *((*unsafe.Pointer)(k2))
}
// ๅฝ้ซ 8 ไฝๅๅธๅผ็ธ็ญๆถ๏ผ่ฟ้่ฆๅฏนๅ
ทไฝๅผ่ฟ่กๆฏ่พ
// ไปฅ้ฟๅ
ๅๅธๅฒ็ชๆถๅผ่ฆ็
if !alg.equal(key, k2) {
continue
}
// ๅฆๆ key ไธญๆฏๆ้๏ผ้ฃไนๆธ
็ฉบ key ็ๅ
ๅฎน
if t.indirectkey {
*(*unsafe.Pointer)(k) = nil
} else if t.key.kind&kindNoPointers == 0 {
memclrHasPointers(k, t.key.size)
}
// ่ฎก็ฎ value ๆๅจ็ๅ
ๅญๅฐๅ
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
// ๅไธ้ข key ็้ป่พๅทฎไธๅค
if t.indirectvalue {
*(*unsafe.Pointer)(v) = nil
} else if t.elem.kind&kindNoPointers == 0 {
memclrHasPointers(v, t.elem.size)
} else {
memclrNoHeapPointers(v, t.elem.size)
}
// ่ฎพ็ฝฎ tophash[i] = 0
b.tophash[i] = empty
// hmap ็ๅคงๅฐ่ฎกๆฐ -1
h.count--
break search
}
}
if h.flags&hashWriting == 0 {
throw("concurrent map writes")
}
h.flags &^= hashWriting
}
Go ็ map ๆฏไธไผ็ผฉๅฎน็๏ผ้ค้ไฝ ๆๆดไธช map ๅ ๆ:
ๆฉๅฎน่งฆๅๅจ mapassign ไธญ๏ผๆไปฌไนๅๆณจ้่ฟไบ๏ผไธป่ฆๆฏไธค็น:
- ๆฏไธๆฏๅทฒ็ปๅฐไบ load factor ็ไธด็็น๏ผๅณๅ ็ด ไธชๆฐ >= ๆกถไธชๆฐ * 6.5๏ผ่ฟๆถๅ่ฏดๆๅคง้จๅ็ๆกถๅฏ่ฝ้ฝๅฟซๆปกไบ๏ผๅฆๆๆๅ ฅๆฐๅ ็ด ๏ผๆๅคงๆฆ็้่ฆๆๅจ overflow ็ๆกถไธใ
- overflow ็ๆกถๆฏไธๆฏๅคชๅคไบ๏ผๅฝ bucket ๆปๆฐ < 2 ^ 15 ๆถ๏ผๅฆๆ overflow ็ bucket ๆปๆฐ >= bucket ็ๆปๆฐ๏ผ้ฃไนๆไปฌ่ฎคไธบ overflow ็ๆกถๅคชๅคไบใๅฝ bucket ๆปๆฐ >= 2 ^ 15 ๆถ๏ผ้ฃๆไปฌ็ดๆฅๅ 2 ^ 15 ๆฏ่พ๏ผoverflow ็ bucket >= 2 ^ 15 ๆถ๏ผๅณ่ฎคไธบๆบขๅบๆกถๅคชๅคไบใไธบๅฅไผๅฏผ่ด่ฟ็งๆ ๅตๅข๏ผๆฏๅ ไธบๆไปฌๅฏน map ไธ่พนๆๅ ฅ๏ผไธ่พนๅ ้ค๏ผไผๅฏผ่ดๅ ถไธญๅพๅคๆกถๅบ็ฐ็ฉบๆด๏ผ่ฟๆ ทไฝฟๅพ bucket ไฝฟ็จ็ไธ้ซ๏ผๅผๅญๅจๅพๆฏ่พ็จ็ใๅจๆฅๆพๆถๆ็ไผไธ้ใ
ไธค็งๆ ๅตๅฎๆน้็จไบไธๅ็่งฃๅณๆนๆณ:
- ้ๅฏน 1๏ผๅฐ B + 1๏ผ่ฟ่ hmap ็ bucket ๆฐ็ปๆฉๅฎนไธๅ๏ผ
- ้ๅฏน 2๏ผ้่ฟ็งปๅจ bucket ๅ ๅฎน๏ผไฝฟๅ ถๅพๅไบ็ดงๅฏๆๅไป่ๆ้ซ bucket ๅฉ็จ็ใ
ๅฎ้ ไธ่ฟ้่ฟๆไธ็ง้บป็ฆ็ๆ ๅต๏ผๅฆๆ map ไธญๆๅคง้็ๅๅธๅฒ็ช็่ฏ๏ผไนไผๅฏผ่ด่ฝๅ ฅ 2 ไธญ็ๅคๆญ๏ผ่ฟๆถๅๅฏน bucket ็ๅ ๅฎน่ฟ่ก็งปๅจๅ ถๅฎๆฒกไปไนๆไน๏ผๅ่ๆฏ็บฏ็ฒน็ๆ ็จๅ๏ผๆไปฅ็่ฎบไธๅญๅจๅฏน Go ็ map ่ฟ่ก hash ็ขฐๆๆปๅป็ๅฏ่ฝๆงใ
ไฝ Go ็ๆฏไธไธช map ้ฝไผๅจๅๅงๅ้ถๆฎต็ makemap ๆถๅฎไธไธช้ๆบ็ hash seed๏ผๆไปฅ่ฆๆ้ ่ฟ็งๅฒ็ชๆฏๆฒก้ฃไนๅฎนๆ็ใ
็็ hashGrow ็ๅ ทไฝๆต็จ:
func hashGrow(t *maptype, h *hmap) {
// ๅฆๆๅทฒ็ป่ถ
่ฟไบ load factor ็้ๅผ๏ผ้ฃไน้่ฆๅฏน map ่ฟ่กๆฉๅฎน๏ผๅณ B = B + 1๏ผbucket ๆปๆฐไผๅไธบๅๆฅ็ไบๅ
// ๅฆๆ่ฟๆฒกๅฐ้ๅผ๏ผ้ฃไนๅช้่ฆไฟๆ็ธๅๆฐ้็ bucket๏ผๆจชๅๆๅนณๅฐฑ่กไบ
bigger := uint8(1)
if !overLoadFactor(h.count+1, h.B) {
bigger = 0
h.flags |= sameSizeGrow
}
oldbuckets := h.buckets
newbuckets, nextOverflow := makeBucketArray(t, h.B+bigger, nil)
flags := h.flags &^ (iterator | oldIterator)
if h.flags&iterator != 0 {
flags |= oldIterator
}
// ๆไบคๆฉๅฎน็ปๆ
h.B += bigger
h.flags = flags
h.oldbuckets = oldbuckets
h.buckets = newbuckets
h.nevacuate = 0
h.noverflow = 0
if h.extra != nil && h.extra.overflow != nil {
// ๆๅฝๅ็ overflow ่ตๅผ็ป oldoverflow
if h.extra.oldoverflow != nil {
throw("oldoverflow is not nil")
}
h.extra.oldoverflow = h.extra.overflow
h.extra.overflow = nil
}
if nextOverflow != nil {
if h.extra == nil {
h.extra = new(mapextra)
}
h.extra.nextOverflow = nextOverflow
}
// ๅฎ้
็ๅๅธ่กจๅ
็ด ็ๆท่ดๅทฅไฝๆฏๅจ growWork ๅ evacuate ไธญๅข้ๆ
ขๆ
ขๅฐ่ฟ่ก็
}
// makeBucketArray ไธบ map buckets ๅๅงๅๅบๅฑๆฐ็ป
// 1<<b ๆฏ้่ฆๅ้
็ๆๅฐๆฐ้ buckets
// dirtyalloc ่ฆไนๆฏ nil๏ผ่ฆไนๅฐฑๆฏไนๅ็ฑ makeBucketArray ไฝฟ็จๅๆ ท็ t ๅ b ๅๆฐ
// ๅ้
็ๆฐ็ป
// ๅฆๆ dirtyalloc ๆฏ nil๏ผ้ฃไนๅฐฑไผๅ้
ไธไธชๆฐๆฐ็ป๏ผๅฆๅไผๆธ
็ฉบๆๅๆฅ็ dirtyalloc
// ็ถๅ้็จ่ฟ้จๅๅ
ๅญไฝไธบๆฐ็ๅบๅฑๆฐ็ป
func makeBucketArray(t *maptype, b uint8, dirtyalloc unsafe.Pointer) (buckets unsafe.Pointer, nextOverflow *bmap) {
// base = 1 << b
base := bucketShift(b)
nbuckets := base
// ๅฏนไบๆฏ่พๅฐ็ b ๆฅ่ฏด๏ผไธๅคชๅฏ่ฝๆ overflow buckets
// ่ฟ้็ๆไธไบ่ฎก็ฎๆถ่
if b >= 4 {
// Add on the estimated number of overflow buckets
// required to insert the median number of elements
// used with this value of b.
nbuckets += bucketShift(b - 4)
sz := t.bucket.size * nbuckets
up := roundupsize(sz)
if up != sz {
nbuckets = up / t.bucket.size
}
}
if dirtyalloc == nil {
buckets = newarray(t.bucket, int(nbuckets))
} else {
// dirtyalloc ไนๅๅฐฑๆฏ็จไธ้ข็ newarray(t.bucket, int(nbuckets))
// ็ๆ็๏ผๆไปฅๆฏ้็ฉบ
buckets = dirtyalloc
size := t.bucket.size * nbuckets
if t.bucket.kind&kindNoPointers == 0 {
memclrHasPointers(buckets, size)
} else {
memclrNoHeapPointers(buckets, size)
}
}
if base != nbuckets {
// ๆไปฌ้ขๅ้
ไบไธไบ overflow buckets
// ไธบไบ่ฎฉ่ฟฝ่ธช่ฟไบ overflow buckets ็ๆๆฌๆไฝ
// ๆไปฌ่ฟ้็บฆๅฎ๏ผๅฆๆ้ขๅ้
็ overflow bucket ็ overflow ๆ้ๆฏ nil
// ้ฃไน there are more available by bumping the pointer.
// ๆไปฌ้่ฆไธไธชๅฎๅ
จ็้็ฉบๆ้ๆฅไฝไธบ last overflow bucket๏ผ็ดๆฅ็จ buckets ๅฐฑ่กไบ
nextOverflow = (*bmap)(add(buckets, base*uintptr(t.bucketsize)))
last := (*bmap)(add(buckets, (nbuckets-1)*uintptr(t.bucketsize)))
last.setoverflow(t, (*bmap)(buckets))
}
return buckets, nextOverflow
}
func growWork(t *maptype, h *hmap, bucket uintptr) {
// ็กฎไฟๆไปฌ็งปๅจ็ oldbucket ๅฏนๅบ็ๆฏๆไปฌ้ฉฌไธๅฐฑ่ฆ็จๅฐ็้ฃไธไธช
evacuate(t, h, bucket&h.oldbucketmask())
// ๅฆๆ่ฟๅจ growing ็ถๆ๏ผๅๅค็งปๅจไธไธช oldbucket
if h.growing() {
evacuate(t, h, h.nevacuate)
}
}
func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
newbit := h.noldbuckets()
if !evacuated(b) {
// TODO: reuse overflow buckets instead of using new ones, if there
// is no iterator using the old buckets. (If !oldIterator.)
// xy ๅ
ๅซ็ๆฏ็งปๅจ็็ฎๆ
// x ่กจ็คบๆฐ bucket ๆฐ็ป็ๅ(low)ๅ้จๅ
// y ่กจ็คบๆฐ bucket ๆฐ็ป็ๅ(high)ๅ้จๅ
var xy [2]evacDst
x := &xy[0]
x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize)))
x.k = add(unsafe.Pointer(x.b), dataOffset)
x.v = add(x.k, bucketCnt*uintptr(t.keysize))
if !h.sameSizeGrow() {
// ๅฆๆ map ๅคงๅฐ(hmap.B)ๅขๅคงไบ๏ผ้ฃไนๆไปฌๅช่ฎก็ฎ y
// ๅฆๅ GC ๅฏ่ฝไผ็ๅฐๆๅ็ๆ้
y := &xy[1]
y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize)))
y.k = add(unsafe.Pointer(y.b), dataOffset)
y.v = add(y.k, bucketCnt*uintptr(t.keysize))
}
for ; b != nil; b = b.overflow(t) {
k := add(unsafe.Pointer(b), dataOffset)
v := add(k, bucketCnt*uintptr(t.keysize))
for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(t.keysize)), add(v, uintptr(t.valuesize)) {
top := b.tophash[i]
if top == empty {
b.tophash[i] = evacuatedEmpty
continue
}
if top < minTopHash {
throw("bad map state")
}
k2 := k
if t.indirectkey {
k2 = *((*unsafe.Pointer)(k2))
}
var useY uint8
if !h.sameSizeGrow() {
// ่ฎก็ฎๅๅธ๏ผไปฅๅคๆญๆไปฌ็ๆฐๆฎ่ฆ่ฝฌ็งปๅฐๅชไธ้จๅ็ bucket
// ๅฏ่ฝๆฏ x ้จๅ๏ผไนๅฏ่ฝๆฏ y ้จๅ
hash := t.key.alg.hash(k2, uintptr(h.hash0))
if h.flags&iterator != 0 && !t.reflexivekey && !t.key.alg.equal(k2, k2) {
// ไธบไปไน่ฆๅ reflexivekey ็ๅคๆญ๏ผๅฏไปฅๅ่่ฟ้:
// https://go-review.googlesource.com/c/go/+/1480
// key != key๏ผๅชๆๅจ float ๆฐ็ NaN ๆถไผๅบ็ฐ
// ๆฏๅฆ:
// n1 := math.NaN()
// n2 := math.NaN()
// fmt.Println(n1, n2)
// fmt.Println(n1 == n2)
// ่ฟ็งๆ
ๅตไธ n1 ๅ n2 ็ๅๅธๅผไนๅฎๅ
จไธไธๆ ท
// ่ฟ้ๅฎๆน่กจ็คบ่ฟ็งๆ
ๅตๆฏไธๅฏๅค็ฐ็
// ้่ฆๅจ iterators ๅไธ็ๆ
ๅตไธๆ่ฝๅค็ฐ
// ไฝๆฏๅฏนไบ่ฟ็ง key ๆไปฌไนๅฏไปฅ้ๆๅฏนๅ
ถ็ฎๆ ่ฟ่กๅ้
// ๅๆถ tophash ๅฏนไบ NaN ไนๆฒกๅฅๆไน
// ่ฟๆฏๆๆญฃๅธธ็ๆ
ๅตไธ็ฎไธไธช้ๆบ็ tophash
// ็ถๅๅ
ฌๅนณๅฐๆ่ฟไบ key ๅนณๅๅๅธๅฐๅ bucket ๅฐฑๅฅฝ
useY = top & 1 // ่ฎฉ่ฟไธช key 50% ๆฆ็ๅป Y ๅๅบ
top = tophash(hash)
} else {
// ่ฟ้ๅ็ๆฏ่พ trick
// ๆฏๅฆๅฝๅๆ 8 ไธชๆกถ
// ้ฃไนๅฆๆ hash & 8 != 0
// ้ฃไน่ฏดๆ่ฟไธชๅ
็ด ็ hash ่ฟ็งๅฝขๅผ
// xxx1xxx
// ่ๆฉๅฎนๅ็ bucketMask ๆฏ
// 1111
// ๆไปฅๅฎ้
ไธ่ฟไธชๅฐฑๆฏ
// xxx1xxx & 1000 > 0
// ่ฏดๆ่ฟไธชๅ
็ด ๅจๆฉๅฎนๅไธๅฎไผๅปไธๅๅบ๏ผๅณY้จๅ
// ๆไปฅๅฐฑๆฏ useY ไบ
if hash&newbit != 0 {
useY = 1
}
}
}
if evacuatedX+1 != evacuatedY {
throw("bad evacuatedN")
}
b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY
dst := &xy[useY] // ็งปๅจ็ฎๆ
if dst.i == bucketCnt {
dst.b = h.newoverflow(t, dst.b)
dst.i = 0
dst.k = add(unsafe.Pointer(dst.b), dataOffset)
dst.v = add(dst.k, bucketCnt*uintptr(t.keysize))
}
dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check
if t.indirectkey {
*(*unsafe.Pointer)(dst.k) = k2 // ๆท่ดๆ้
} else {
typedmemmove(t.key, dst.k, k) // ๆท่ดๅผ
}
if t.indirectvalue {
*(*unsafe.Pointer)(dst.v) = *(*unsafe.Pointer)(v)
} else {
typedmemmove(t.elem, dst.v, v)
}
dst.i++
// These updates might push these pointers past the end of the
// key or value arrays. That's ok, as we have the overflow pointer
// at the end of the bucket to protect against pointing past the
// end of the bucket.
dst.k = add(dst.k, uintptr(t.keysize))
dst.v = add(dst.v, uintptr(t.valuesize))
}
}
// Unlink the overflow buckets & clear key/value to help GC.
if h.flags&oldIterator == 0 && t.bucket.kind&kindNoPointers == 0 {
b := add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))
// Preserve b.tophash because the evacuation
// state is maintained there.
ptr := add(b, dataOffset)
n := uintptr(t.bucketsize) - dataOffset
memclrHasPointers(ptr, n)
}
}
if oldbucket == h.nevacuate {
advanceEvacuationMark(h, t, newbit)
}
}
func advanceEvacuationMark(h *hmap, t *maptype, newbit uintptr) {
h.nevacuate++
// Experiments suggest that 1024 is overkill by at least an order of magnitude.
// Put it in there as a safeguard anyway, to ensure O(1) behavior.
stop := h.nevacuate + 1024
if stop > newbit {
stop = newbit
}
for h.nevacuate != stop && bucketEvacuated(t, h, h.nevacuate) {
h.nevacuate++
}
if h.nevacuate == newbit { // newbit == # of oldbuckets
// ๅคงๅฐๅข้ฟๅ
จ้จ็ปๆใ้ๆพ่็ bucket array
h.oldbuckets = nil
// ๅๆ ทๅฏไปฅไธขๅผ่็ overflow buckets
// ๅฆๆๅฎไปฌ่ฟ่ขซ่ฟญไปฃๅจๆๅผ็จ็่ฏ
// ่ฟญไปฃๅจไผๆๆไธไปฝๆๅ slice ็ๆ้
if h.extra != nil {
h.extra.oldoverflow = nil
}
h.flags &^= sameSizeGrow
}
}
ไปฃ็ ็็ๆฏ่พๆฝ่ฑก๏ผๅ่กฅไธคไธชๅพ:
- sameSizeGrow
โโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโ
โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โโโโโโโโโโโโผโโโโโโโโโโโดโโโโโโฌโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโ โ tophash: 10 โ
โ empty โ โ lowbits: 1001 โ
โ โโโโโโโโ โโโโโโโโโโโโโโโโโโค
โโโโโโโโโโโโโโโโโโค โ โ empty โ
โ empty โ โ โ โ
โ โ โ โโโโโโโโโโโโโโโโโโค
โโโโโโโโโโโโโโโโโโค โ โ empty โ
โ empty โ โ โ โ
โ โ โ โ โโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโโโโโค โ โ tophash: 23 โ
โ โ empty โ โ โ lowbits: 0001 โ
โ โ โ โ โโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโโโโโค โ โ empty โ
โโโโโโโโโโโโ โ โ empty โ โ โ โ
โ before โ โ โ โ โ โโโโโโโโโโโโโโโโโโค
โโโโโโโโโโโโ โ โโโโโโโโโโโโโโโโโโค โ โ tophash: 100 โ
โ โ empty โ โ โ lowbits: 0001 โ
โ โ โ โ โโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโโโโโค โ โ empty โ
โ โ tophash: 15 โ โ โ โ
โ โ lowbits: 0001 โ โ โโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโโโโโค โ โ empty โ
โ โ empty โ โ โ โ
โ โ โ โ โโโโโโโโโโโโฌโโโโโโ
โ โโโโโโโโโโโโโโโโโโ โโโโโโโโโ overflow โ
โ โโโโโโโโโโโโ
โ
โ
โ
โ
โ โโโโโโโโโโโโโโโโโโ
โ โ tophash: 10 โ
โ โ lowbits: 1001 โ
โ โโโโโโโโโโโโโโโโโโค
โ โ tophash: 23 โ
โ โ lowbits: 0001 โ
โ โโโโโโโโโโโโโโโโโโค
โ โ tophash: 100 โ
โ โ lowbits: 0001 โ
โ โโโโโโโโโโโโโโโโโโค
โ โ tophash: 15 โ
โ โ lowbits: 0001 โ
โ โโโโโโโโโโโโโโโโโโค
โโโโโโโโโโโโ โ โ empty โ
โ after โ โ โ โ
โโโโโโโโโโโโ โ โโโโโโโโโโโโโโโโโโค
โ โ empty โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโค
โ โ empty โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโค
โ โ empty โ
โ โ โ
โ โโโโโโโโโโโโผโโโโโโโโโโโฌโโโโโโดโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโ
โ โ 0 โ 1 โ 2 โ 3 โ 4 โ 5 โ 6 โ 7 โ
โ โโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโค
โ โ โ
โ โ โ
โ โ โ
โ โ โ
โ โ โ
โ โ โ
โ โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ X part โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถโ
โ โ โ
โผ โ โ
โ โ
โ โ
โ โ
sameSizeGrow ไนๅ๏ผๆฐๆฎๆๅๆด็ดงๅใ
- biggerSizeGrow
โโโโโโโโโโโโ โโโโโโโโโโโโฌโโโโโโโโโโโ
โ 0 โ โ 0 โ โฒ
โโโโโโโโโโโโผโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโค โ
โ 1 โ tophash: 10 โ tophash:23 โ โโโโโโโถโ 1 โ โ
โโโโโโโโโโโโค lowbits: 1001 โ low bits: 0001 โโโโโโโโ โโโโโโโโโโโโค โ
โ 2 โโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโ โ 2 โ โ
โโโโโโโโโโโโค โ โโโโโโโโโโโโค
โ 3 โ โ โ 3 โ
โโโโโโโโโโโโค โ โโโโโโโโโโโโค X part
โ 4 โ โ โ 4 โ
โโโโโโโโโโโโค โ โโโโโโโโโโโโค
โ 5 โ โ โ 5 โ โ
โโโโโโโโโโโโค โ โโโโโโโโโโโโค โ
โ 6 โ โ โ 6 โ โ
โโโโโโโโโโโโค โ โโโโโโโโโโโโค โ
โ 7 โ โ โ 7 โ โผ
โโโโโโโโโโโโ โ โโโโโโโโโโโโผโโโโโโโโโโโ
โ โ 8 โ โฒ
โ โโโโโโโโโโโโค โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโถโ 9 โ โ
โโโโโโโโโโโโค โ
โ 10 โ โ
โโโโโโโโโโโโค
โ 11 โ
โโโโโโโโโโโโค Y part
โ 12 โ
โโโโโโโโโโโโค
โ 13 โ โ
โโโโโโโโโโโโค โ
โ 14 โ โ
โโโโโโโโโโโโค โ
โ 15 โ โผ
โโโโโโโโโโโโดโโโโโโโโโโโ
ๆกถๆฐ็ปๅขๅคงๅ๏ผๅๆฅๅไธไธชๆกถ็ๆฐๆฎๅฏไปฅ่ขซๅๅซ็งปๅจๅฐไธๅๅบๅไธๅๅบใ
ๅจไธ้ข็ไปฃ็ ไธญๆไปฌ่ง่ฟๆ ๆฐๆฌก็ indirectkey ๅ indirectvalueใindirectkey ๅ indirectvalue ๅจ map ้ๅฎ้ ๅญๅจ็ๆฏๆ้๏ผไผ้ ๆ GC ๆซๆๆถ๏ผๆซๆๆดๅค็ๅฏน่ฑกใ่ณไบๆฏๅฆๆฏ indirect๏ผไพ็ถๆฏ็ฑ็ผ่ฏๅจๆฅๅณๅฎ็๏ผไพๆฎๆฏ:
- key > 128 ๅญ่ๆถ๏ผindirectkey = true
- value > 128 ๅญ่ๆถ๏ผindirectvalue = true
ๆไปฌๅฏไปฅ็จ lldb ๆฅ่ฟ่ก็ฎๅ้ช่ฏ:
package main
import "fmt"
func main() {
type P struct {
Age [16]int
}
var a = map[P]int{}
a[P{}] = 1
fmt.Println(a)
}
ๅจ lldb ไธญๅฏไปฅ็ๅฐ indirectkey ไธบ falseใ
(lldb) b mapassign
(lldb) p *t
(runtime.maptype) *t = {
typ = {
size = 0x0000000000000008
ptrdata = 0x0000000000000008
hash = 2678392653
tflag = 2
align = 8
fieldalign = 8
kind = 53
alg = 0x0000000001137020
gcdata = 0x00000000010cf298
str = 26128
ptrToThis = 0
}
key = 0x00000000010a77a0
elem = 0x000000000109d180
bucket = 0x00000000010aea00
hmap = 0x00000000010b4da0
keysize = 128 =======> 128 ๅญ่
indirectkey = false =====> false
valuesize = 8
indirectvalue = false
bucketsize = 1104
reflexivekey = true
needkeyupdate = false
}
็ป P ๅ ไธไธชๅญ่:
package main
import "fmt"
func main() {
type P struct {
Age [16]int
Male bool
}
var a = map[P]int{}
a[P{}] = 1
fmt.Println(a)
}
indirectkey ๅๆไบ true:
(lldb) p *t
(runtime.maptype) *t = {
typ = {
size = 0x0000000000000008
ptrdata = 0x0000000000000008
hash = 2678392653
tflag = 2
align = 8
fieldalign = 8
kind = 53
alg = 0x0000000001137020
gcdata = 0x00000000010cf3b8
str = 26176
ptrToThis = 0
}
key = 0x00000000010a92c0
elem = 0x000000000109d280
bucket = 0x00000000010aeb20
hmap = 0x00000000010b4ec0
keysize = 8 ======> ๅๆไบ 8 ๅญ่็ๆ้
indirectkey = true ======> ๅๆไบ true
valuesize = 8
indirectvalue = false
bucketsize = 144
reflexivekey = true
needkeyupdate = false
}
indirectvalue ไนๆฏๅฎๅ จไธๆ ท็๏ผ่ถ ่ฟ 128 ๅญ่(ไธๅซ)ๆถ๏ผไผ่ขซ่ตๅผไธบ true๏ผๅนถ้ๅไธบๆ้ใ
ๆ่ทฏ๏ผไป nextOverflow ไธญๆฟ overflow bucket๏ผๅฆๆๆฟๅฐ๏ผๅฐฑๆพ่ฟ hmap.extra.overflow ๆฐ็ป๏ผๅนถ่ฎฉ bmap ็ overflow pointer ๆๅ่ฟไธช bucketใ
ๅฆๆๆฒกๆพๅฐ๏ผ้ฃๅฐฑ new ไธไธชใ
func (h *hmap) newoverflow(t *maptype, b *bmap) *bmap {
var ovf *bmap
if h.extra != nil && h.extra.nextOverflow != nil {
// We have preallocated overflow buckets available.
// See makeBucketArray for more details.
ovf = h.extra.nextOverflow
if ovf.overflow(t) == nil {
// We're not at the end of the preallocated overflow buckets. Bump the pointer.
h.extra.nextOverflow = (*bmap)(add(unsafe.Pointer(ovf), uintptr(t.bucketsize)))
} else {
// This is the last preallocated overflow bucket.
// Reset the overflow pointer on this bucket,
// which was set to a non-nil sentinel value.
ovf.setoverflow(t, nil)
h.extra.nextOverflow = nil
}
} else {
ovf = (*bmap)(newobject(t.bucket))
}
h.incrnoverflow()
if t.bucket.kind&kindNoPointers != 0 {
h.createOverflow()
*h.extra.overflow = append(*h.extra.overflow, ovf)
}
b.setoverflow(t, ovf)
return ovf
}
func (h *hmap) createOverflow() {
if h.extra == nil {
h.extra = new(mapextra)
}
if h.extra.overflow == nil {
h.extra.overflow = new([]*bmap)
}
}
// incrnoverflow increments h.noverflow.
// noverflow counts the number of overflow buckets.
// This is used to trigger same-size map growth.
// See also tooManyOverflowBuckets.
// To keep hmap small, noverflow is a uint16.
// When there are few buckets, noverflow is an exact count.
// When there are many buckets, noverflow is an approximate count.
func (h *hmap) incrnoverflow() {
// We trigger same-size map growth if there are
// as many overflow buckets as buckets.
// We need to be able to count to 1<<h.B.
if h.B < 16 {
h.noverflow++
return
}
// Increment with probability 1/(1<<(h.B-15)).
// When we reach 1<<15 - 1, we will have approximately
// as many overflow buckets as buckets.
mask := uint32(1)<<(h.B-15) - 1
// Example: if h.B == 18, then mask == 7,
// and fastrand & 7 == 0 with probability 1/8.
if fastrand()&mask == 0 {
h.noverflow++
}
}