如何得到一个 map 占用了多少内存
go get github.com/520MianXiangDuiXiang520/MapSize
package main
import (
"fmt"
"github.com/520MianXiangDuiXiang520/MapSize"
)
func main() {
m := make(map[int]struct{})
for i := 0; i < 100; i++ {
m[i] = struct{}{}
}
fmt.Println(mapsize.Size(m)) // 1416
}
思路:
map 底层是 runtime.hmap
只需要使用 unsafe
将 map 指针对应的内存强转就可以得到 map 申请的桶的个数了,乘以键值的大小就可以算出内存占用情况:
func Size[K comparable, V any](m map[K]V) int64 {
var zeroK K
var zeroValue V
keySize := unsafe.Sizeof(zeroK)
valueSize := unsafe.Sizeof(zeroValue)
vo := reflect.ValueOf(m)
hm := (*hmap)(unsafe.Pointer(vo.Pointer()))
bn := 1<<hm.B + uintptr(hm.noverflow)
bz := unsafe.Sizeof(bmap{}) + (keySize+valueSize)*bucketCnt
return int64(unsafe.Sizeof(hmap{}) + bz*bn)
}
注意:由于 noverflow 并不是真实的溢出桶数量,所以这种方法得到内存占用并不完全准确,但 map 本身的阔缩容用的也是 noverflow 所以与实际情况并不会差很多,通过 pprof 测试也几乎一致