加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

字典 – 如何在golang中获取变量的内存大小?

发布时间:2020-12-16 19:20:58 所属栏目:大数据 来源:网络整理
导读:我很好奇地图和切片的内存成本,所以我写了一个比较大小的程序.我通过unsafe.Sizeof(s)得到内存大小,但显然它是错误的,因为当我改变大小时,输出是相同的. func getSlice(size int) []int { t := time.Now() s := make([]int,size*2) for i := 0; i size; i++
我很好奇地图和切片的内存成本,所以我写了一个比较大小的程序.我通过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: %dn",unsafe.Sizeof(s))
    fmt.Printf("map size: %dn",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.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读