如何在golang中获取变量的变量内存大小? [英] How to get variable memory size of variable in golang?

查看:234
本文介绍了如何在golang中获取变量的变量内存大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很好奇 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))
}


解决方案

unsafe.SizeOf() reflect.Type .Size()只返回传递值的大小,不递归遍历数据结构并添加指向值的大小。



切片是相对简单的结构: reflect.SliceHeader ,因为我们知道它引用了一个支持数组,所以我们可以很容易地手动计算它的大小,例如:

 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 {}))

输出(在 Go Playground ):

  [] 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字节)。具有1000 int-int 对的地图大约需要分配42 KB。


I am curious about the memory cost of map and slice, so I wrote a program to compare the sizes. I get the memory size by unsafe.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() and reflect.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() and getMap() 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 1000 int-int pairs required approximately to allocate 42 KB.

这篇关于如何在golang中获取变量的变量内存大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆