Golang--map expansion mechanism (including source code)

1 Equivalent expansion

1.1 Trigger conditions

Too many overflow buckets

  • When B is greater than 15, it is calculated as 15. If the bucket overflows>=2^15 power, triggering equal expansion
  • When B is less than 15, calculated as B, if the bucket overflows>=Greater than 2^B power, triggers equal expansion

1.2 Trigger results

Create a new map of the same size and move the old data there

1.3 Source code

Path: go1.18/src/runtime/map.go

// overflow buckets 太多
func tooManyOverflowBuckets(noverflow uint16, B uint8) bool {
    
    
	// If the threshold is too low, we do extraneous work.
	// If the threshold is too high, maps that grow and shrink can hold on to lots of unused memory.
	// "too many" means (approximately) as many overflow buckets as regular buckets.
	// See incrnoverflow for more details.
	if B > 15 {
    
    
		B = 15
	}
	// The compiler doesn't see here that B < 16; mask B to generate shorter shift code.
	return noverflow >= uint16(1)<<(B&15)
}

2 Incremental expansion

2.1 Trigger conditions

Load factor >6.5

  • Bearing factor: total number of map elements/number of buckets.
  • The total number of map elements is: count in hmap.
  • Number of buckets: 2^B

2.2 Trigger results

Double the capacity and move the data.

2.3 Source code

Path: go1.18/src/runtime/map.go

func overLoadFactor(count int, B uint8) bool {
    
    
	return count > bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen)
    //人话:当count大于8且承载因子大于6.5时可满足要求
}

count (
	bucketCntBits = 3
	bucketCnt     = 1 << bucketCntBits
    
    loadFactorNum = 13
	loadFactorDen = 2
)

// bucketShift returns 1<<b, optimized for code generation. 
// 翻译,返回2的B次方
func bucketShift(b uint8) uintptr {
    
    
	// Masking the shift amount allows overflow checks to be elided.
	return uintptr(1) << (b & (goarch.PtrSize*8 - 1))
}

Guess you like

Origin blog.csdn.net/Srwici/article/details/125410656