我很好奇地图和切片的内存成本,所以我写了一个比较大小的程序.我通过unsafe.Sizeof(s)得到内存大小,但显然它是错误的,因为当我改变大小时,输出是相同的.
func getSlice(size int) []int { t := time.Now() s := make([]int,size*2) for i := 0; i < size; i++ { index := i << 1 s[index] = i s[index+1] = i } fmt.Println("slice time cost: ",time.Since(t)) return s } func getMap(size int) map[int]int { t := time.Now() m := make(map[int]int,size) for i := 0; i < size; i++ { m[i] = i } fmt.Println("map time cost: ",time.Since(t)) return m } func TestMem(t *testing.T) { size := 1000 s := getSlice(size) m := getMap(size) fmt.Printf("slice size: %d\n",unsafe.Sizeof(s)) fmt.Printf("map size: %d\n",unsafe.Sizeof(m)) }
unsafe.SizeOf()
和reflect.Type.Size()仅返回传递值的大小,而不递归遍历数据结构并添加指向值的大小.
切片是一个相对简单的结构:reflect.SliceHeader
,因为我们知道它引用了一个支持数组,我们可以很容易地“手动”计算它的大小,例如:
s := make([]int32,1000) fmt.Println("Size of []int32:",unsafe.Sizeof(s)) fmt.Println("Size of [1000]int32:",unsafe.Sizeof([1000]int32{})) fmt.Println("Real size of s:",unsafe.Sizeof(s)+unsafe.Sizeof([1000]int32{}))
输出(在Go Playground上试试):
Size of []int32: 12 Size of [1000]int32: 4000 Real size of s: 4012
地图是比较复杂的数据结构,我不会详细介绍,但请查看这个问题的答案:Golang: computing the memory footprint (or byte length) of a map
如果你想要“真实”数字,你可以利用Go的测试工具,它也可以执行内存基准测试.传递-benchmem参数,并在基准函数内部仅分配您要测量的内存:
func BenchmarkSlice100(b *testing.B) { for i := 0; i < b.N; i++ { getSlice(100) } } func BenchmarkSlice1000(b *testing.B) { for i := 0; i < b.N; i++ { getSlice(1000) } } func BenchmarkSlice10000(b *testing.B) { for i := 0; i < b.N; i++ { getSlice(10000) } } func BenchmarkMap100(b *testing.B) { for i := 0; i < b.N; i++ { getMap(100) } } func BenchmarkMap1000(b *testing.B) { for i := 0; i < b.N; i++ { getMap(1000) } } func BenchmarkMap10000(b *testing.B) { for i := 0; i < b.N; i++ { getMap(10000) } }
(当然,从getSlice()和getMap()中删除计时和打印调用.)
跑步
go test -bench . -benchmem
输出是:
BenchmarkSlice100-4 3000000 471 ns/op 1792 B/op 1 allocs/op BenchmarkSlice1000-4 300000 3944 ns/op 16384 B/op 1 allocs/op BenchmarkSlice10000-4 50000 39293 ns/op 163840 B/op 1 allocs/op BenchmarkMap100-4 200000 11651 ns/op 2843 B/op 9 allocs/op BenchmarkMap1000-4 10000 111040 ns/op 41823 B/op 12 allocs/op BenchmarkMap10000-4 1000 1152011 ns/op 315450 B/op 135 allocs/op
B / op值告诉您每个op分配了多少字节. allocs / op告诉每个操作发生了多少(不同的)内存分配.
在我的64位体系结构(int的大小为8字节)上,它告诉具有2000个元素的片的大小大约为16 KB(与2000 * 8字节一致).具有1000个int-int对的映射大约需要分配42 KB.