Go闭包如何布置在内存中?

时间:2018-07-24 01:48:56

标签: go closures

有关闭包的一般说明,请参见How do JavaScript closures work?

Go闭包在内存中的布局如何?

例如,使用以下功能:

type M int

func (m *M) Adder(amount int) func() {
    return func() {
        *m = *m + amount
    }
}

当我们的代码调用a := m.Adder()时,堆上分配了多少内存,它看起来像什么?返回的func()值占用多少内存(无论它在内存中的什么位置)?

2 个答案:

答案 0 :(得分:0)

golang常见问题解答可能会有所帮助:https://golang.org/doc/faq#stack_or_heap

我怎么知道是在堆上还是在栈上分配了变量?

从正确性的角度来看,您不需要知道。只要有引用,Go中的每个变量都存在。该实现选择的存储位置与该语言的语义无关。

存储位置确实会影响编写高效的程序。如果可能,Go编译器将在该函数的堆栈框架中分配该函数本地的变量。但是,如果编译器无法证明函数返回后未引用该变量,则编译器必须在垃圾回收堆上分配该变量,以避免悬空指针错误。另外,如果局部变量很大,则将其存储在堆中而不是堆栈中可能更有意义。

在当前的编译器中,如果使用了变量的地址,则该变量是在堆上分配的候选对象。但是,基本的转义分析可以识别某些情况,即此类变量不会超出函数的返回范围,而是可以驻留在堆栈中。

答案 1 :(得分:-1)

  

The Go Programming Language Specification

     

Function literals

     

函数文字代表一个匿名函数。

     

FunctionLit = "func" Signature FunctionBody .

     

func(a, b int, z float64) bool { return a*b < int(z) }

     

可以将函数文字分配给变量或直接调用。

f := func(x, y int) int { return x + y }
func(ch chan int) { ch <- ACK }(replyChan)
     

函数文字是闭包:它们可以引用在中定义的变量   周围的功能。然后,这些变量将在   周围的函数和函数文字,它们作为   只要它们可以访问。


  

闭包可能是指在   周围的功能。然后,这些变量将在   周围的函数和函数文字,它们作为   只要它们可以访问。

可以在函数调用后保留的变量放在堆中。在Go中,关闭实际上就是这么简单。


例如,

func closure() func() *byte {
    var b [4 * 1024]byte
    return func() *byte {
        return &b[0]
    }
}

closure()调用是两个堆分配,一个分配用于16个字节(在amd64上= 8 + 8字节)

struct { F uintptr; b *[4096]byte }

一个为4096字节

[4096]byte

总共4112字节。