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
参数,基准函数内部仅要衡量其内存分配:(从getSlice()
当然getMap()
拆下正和打印话费)
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) }
}
与
运行
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
值告诉你每个操作分配了多少个字节。 allocs/op
表示每个操作有多少(不同的)内存分配。
在我的64位体系结构(其中int
的大小是8个字节)中,它指出具有2000个元素的片大小大约为16 KB(与2000 * 8字节一致)。具有1000个对的地图大约需要分配42 KB。
没有_need_这样做,因为你可以计算所需的空间:切片的大小乘以每个元素的大小。对于地图而言,由于某些内部区域无法访问(例如散列冲突)而变得更加困难,但它基本上是相同的。 – Volker