Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How are Go closures layed out in memory?

Tags:

closures

go

For an explanation of closures in general, see How do JavaScript closures work?

How exactly are Go closures laid out in memory?

Take, for example, the following function:

type M int

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

When our code calls a := m.Adder(), how much memory is allocated on the heap and what does it look like? How much memory does the returned func() value take up (wherever in memory it ends up being)?

like image 702
Riking Avatar asked Jul 24 '18 01:07

Riking


1 Answers

The Go Programming Language Specification

Function literals

A function literal represents an anonymous function.

FunctionLit = "func" Signature FunctionBody .

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

A function literal can be assigned to a variable or invoked directly.

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

Function literals are closures: they may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.


Closures may refer to variables defined in a surrounding function. Those variables are then shared between the surrounding function and the function literal, and they survive as long as they are accessible.

Variables that survive a function call are put on the heap. In Go, closures are really that simple.


For example,

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

A closure() call is two heap allocations, one for 16 (= 8 + 8 on amd64) bytes

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

and one for 4096 bytes

[4096]byte

for a total of 4112 bytes.

like image 153
peterSO Avatar answered Oct 05 '22 02:10

peterSO