问题描述
我很好奇 map
和 slice
的内存开销,所以我编写了一个程序来比较大小。我通过 unsafe.Sizeof(s)
获取内存大小,但显然这是错误的,因为当我改变大小时,输出是相同的。
func getSlice(size int)[] int {
t:= time.Now()
s:= make([] int,size * 2)
for i:= 0;我<尺寸; i ++ {
index:= i<< 1
s [index] = i
s [index + 1] = i
}
fmt.Println(slice time cost:,time.Since(t))
返回s
$ b $ func getMap(size int)map [int] int {
t:= time.Now()
m:= make(map [ int] int,size)
for i:= 0;我<尺寸; 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 \\\
,unsafe.Sizeof(s))
fmt.Printf(map size:%d \\\
,unsafe.Sizeof(m))
}
和 reflect.Type .Size()
只返回传递值的大小,不递归遍历数据结构并添加指向值的大小。
切片是相对简单的结构:,因为我们知道它引用了一个支持数组,所以我们可以很容易地手动计算它的大小,例如:
s:= make([] int32,1000)
fmt.Println([] 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 {}))
输出(在):
[] int32的大小:12
[1000]的大小int32:4000
s的实际大小:4012
地图有更复杂的数据结构,我不会详细讨论,但请查看这个问题+回答:
>如果您想要真实数字,您可以利用Go的测试工具,它也可以执行内存基准测试。传递 -benchmem
参数,并在基准函数内部分配您想要测量的内存:
func BenchmarkSlice100(b * testing.B){
和
for i:= 0;我< b.N; i ++ {getSlice(100)}
}
func BenchmarkSlice1000(b * testing.B){
for i:= 0;我< b.N; i ++ {getSlice(1000)}
}
func BenchmarkSlice10000(b * testing.B){
for i:= 0;我< b.N; i ++ {getSlice(10000)}
}
func BenchmarkMap100(b * testing.B){
for i:= 0;我< b.N; i ++ {getMap(100)}
}
func BenchmarkMap1000(b * testing.B){
for i:= 0;我< b.N; i ++ {getMap(1000)}
}
func BenchmarkMap10000(b * testing.B){
for i:= 0;我< b.N; (取消定时并打印来自
$ code> getSlice()getMap()
当然。)
用
运行
go test -bench。 -benchmem
输出结果为:
BenchmarkSlice 100-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分配/操作
BenchmarkMap10000-4 1000 1152011 ns / op 315450 B / op 135分配/操作
B / op
值会告诉您每个操作分配了多少个字节。allocs / op
告诉每个操作系统有多少(不同的)内存分配。
在我的64位架构其中
int
的大小为8个字节),它表明具有2000个元素的切片的大小大致为16KB(符合2000 * 8字节)。具有1000int-int
对的地图大约需要分配42 KB。I am curious about the memory cost of
map
andslice
, so I wrote a program to compare the sizes. I get the memory size byunsafe.Sizeof(s)
, but obviously it is wrong, because when I change the size, the output is the same.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()
andreflect.Type.Size()
only return the size of the passed value without recursively traversing the data structure and adding sizes of pointed values.The slice is relatively a simple struct:
reflect.SliceHeader
, and since we know it references a backing array, we can easily compute its size "manually", e.g.: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{}))
Output (try it on the Go Playground):
Size of []int32: 12 Size of [1000]int32: 4000 Real size of s: 4012
Maps are a lot more complex data structures, I won't go into details, but check out this question+answer: Golang: computing the memory footprint (or byte length) of a map
If you want "real" numbers, you may take advantage of the testing tool of Go, which can also perform memory benchmarking. Pass the
-benchmem
argument, and inside the benchmark function allocate only whose memory you want to measure: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) } }
(Remove the timing and printing calls from
getSlice()
andgetMap()
of course.)Running with
go test -bench . -benchmem
Output is:
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
values tell you how many bytes were allocated per op.allocs/op
tells how many (distinct) memory allocations occurred per op.On my 64-bit architecture (where the size of
int
is 8 bytes) it tells that the size of a slice having 2000 elements is roughly 16 KB (in line with 2000 * 8 bytes). A map with 1000int-int
pairs required approximately to allocate 42 KB.这篇关于如何在golang中获取变量的变量内存大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!