如何理解Go语言中的动态内存分配和静态内存分配?

我已经不仅一次听说,Go的性能测试中,有关于 0内存分配 这种说法了,今天在看一个Go的路由器的说明时,再一次看到这种说法。

我已经百度过了动态内存分配和静态内存分配,主要说C语言,但Go语言中没有主动malloc这种C语言的形式。请问,如何理解Go语言中的动态内存分配和静态内存分配?

已邀请:

Ky

赞同来自: dcb9

snipaste20170119_171431.png 还是上图吧,图中是数组编译后的反汇编,可以看到这里的数组长度和数据存放 snipaste20170119_171922.png 还有这张图中对数据数组的访问,是以绝对地址来访问的,在整个程序中都不会改变,跟字符串一样

所以像数组这种就是静态分配,在编译时就确定了 而切片是动态的。。。真的是动态的,真的是动态的,真的是动态的 无论是设置了len或是cap,他总是可以被改动的,所以它不能跟数组一样用绝对地址来访问

能理解了吗

Ky

赞同来自: toukii

再说一句,他说零分配内存,并不是真的零分配内存,因为你的程序不可能不分配内存 而是它在用起来的时候(提供的功能),不涉及到内存分配,因为都已经初始化完成或是缓存完成,他测Benchmark的时候自然0分配

Ky

赞同来自: btfak

@imjj 我做了个动图,看的方便些,图里是个循环,用的是楼上的代码 图里最后显示的是切片的结构 指针+长度,这个是1.7.4的反汇编 现在的1.8优化更强,应该能达到数组的效率,不过我没仔细看 当然了这个的结果还是以自己的为准,我的仅供参考,哈哈

Ky

赞同来自:

给切片动态加值就会malloc内存

toukii

赞同来自:

看到过这样一句话:

When declaring a slice, use

var t []string

rather than

t := []string{}

The former avoids allocating memory if the slice is never appended to.

我的理解是,第二种写法是静态分配内存,第一种写法没有分配内存;如果使用append,若len大于cap,slice会重新分配内存,这种称为动态分配内存。

Ky

赞同来自:

func Benchmark1(b *testing.B) {
    for i := 0; i < b.N; i++ {
        var array [7]byte
        array[0] = 10
    }
}
func Benchmark2(b *testing.B) {
    for i := 0; i < b.N; i++ {
        var slice []byte
        slice = append(slice, 10)
    }
}

// Benchmark1-2     0 B/op         0 allocs/op
// Benchmark2-2     8 B/op         1 allocs/op

这样就可以看出来。 数组的话,go 会在编译时预分配内存空间,而切片则是运行时动态申请内存

Ky

赞同来自:

    a := []int{1, 2, 3, 4, 5, 6}
    for i := 0; i < len(a); i++ {
        _ = a[i]
    }

再给你举个例子,如果像这样遍历切片,你看一下反汇编,这里的len是每次循环都会计算一次的。 而如果这个a是一个数组,那么编译过后, len(a) 直接被编译为了6,不需要再计算了。 原因就是切片是不固定大小的,可大可小,所以必须每次都要计算,而数组却不需要。 所以以这个现象来看数组就是个固定内存,它的大小不会变,甚至指针也不会变

上面都是我自己的理解。。。也可能有错

要回复问题请先登录注册