rog*_*ger 6 memory dictionary go slice
我好奇的存储成本map和slice,所以我写了一个程序来比较大小.我得到了内存大小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))
}
Run Code Online (Sandbox Code Playgroud)
icz*_*cza 11
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{}))
Run Code Online (Sandbox Code Playgroud)
输出(在Go Playground上试试):
Size of []int32: 12
Size of [1000]int32: 4000
Real size of s: 4012
Run Code Online (Sandbox Code Playgroud)
地图是更复杂的数据结构,我不会详细介绍,但请查看这个问题+答案:Golang:计算地图的内存占用(或字节长度)
如果你想要"真实"数字,你可以利用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) }
}
Run Code Online (Sandbox Code Playgroud)
(删除来自定时和印刷呼叫getSlice()和getMap()当然).
跑步
go test -bench . -benchmem
Run Code Online (Sandbox Code Playgroud)
输出是:
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
Run Code Online (Sandbox Code Playgroud)
B/op值告诉你每个op分配了多少字节.allocs/op告诉每个操作发生了多少(不同的)内存分配.
在我的64位架构(其大小int为8字节)上,它告诉具有2000个元素的片的大小大约是16KB(与2000*8字节一致).int-int需要1000 对的地图大约需要分配42 KB.
Rod*_*igo 10
这会产生一些编组开销,但我发现这是在运行时获取 go 中值大小的最简单方法。对于我的需要,编组开销不是一个大问题,所以我走这条路。
func getRealSizeOf(v interface{}) (int, error) {
b := new(bytes.Buffer)
if err := gob.NewEncoder(b).Encode(v); err != nil {
return 0, err
}
return b.Len(), nil
}
Run Code Online (Sandbox Code Playgroud)