summary
A variable is defined in Go. Whether it is allocated on the heap or on the stack. The official Go document tells us that it doesn't need to be controlled. They will analyze it. In fact, this analysis is escape analysis
Generally speaking, when the pointer of an object is referenced by multiple methods or threads, we call the pointer an escape.
Basic principles of Golang memory allocation
If there is no reference outside the function, it will be put on the stack first;
If there is a reference outside the function, it must be placed in the heap;
If a variable is too large, it may be allocated on the heap
escape analysis
Variables allocate memory on the stack or heap, which is determined by the compiler
When build ing, you can view the escape analysis in the compilation process by adding the - gcflags "-m" compilation parameter
Why escape analysis
When it comes to escape analysis, we have to mention the difference between heap allocation and stack allocation.
Heap is suitable for memory allocation of unpredictable size. However, the price paid for this is that the distribution speed is slow and will form Memory fragmentation . Another big problem with heap allocation is gc, which consumes cpu time. Reducing memory escape directly reduces the gc processing time.
Stack memory allocation will be very fast. Stack memory allocation requires only two CPU instructions: "PUSH" and "RELEASE" allocation and RELEASE; For heap memory allocation, you first need to find a memory block of appropriate size. Then it can be released through garbage collection.
case
Pointer escape
code
1 package main 2 3 func main() { 4 test() 5 } 6 7 func test() *int { 8 i := 1 9 return &i 10 }
compile
% go build -gcflags "-m" ./main.go:7:6: can inline test ./main.go:3:6: can inline main ./main.go:4:9: inlining call to test ./main.go:8:5: moved to heap: i
explain
Although i is a local variable declared by the test function, golang supports the extension of the scope of variable i outside the function by allocating the variable on heap through memory escape.
Escape caused by insufficient stack space
code
func main() { stack() } func stack() { s := make([]int, 100000, 100000) s[0] = 1 }
compile
% go build -gcflags "-m" ./main.go:7:6: can inline stack ./main.go:3:6: can inline main ./main.go:4:10: inlining call to stack ./main.go:4:10: make([]int, 100000, 100000) escapes to heap ./main.go:8:14: make([]int, 100000, 100000) escapes to heap
explain
The stack size is limited. If the variable is too large, it will be allocated directly to the heap.
If the cap of slice in the above case is set to 10 and analyzed in the same way, memory escape will not occur.
The memory allocation method using new is the same as that of make.
Dynamic type escape
code
3 func main() { 4 dynamic() 5 } 6 7 func dynamic() interface{} { 8 i := 0 9 return i 10 }
compile
% go build -gcflags "-m" ./main.go:7:6: can inline dynamic ./main.go:3:6: can inline main ./main.go:4:12: inlining call to dynamic ./main.go:4:12: i does not escape ./main.go:9:5: i escapes to heap
explain
We can see that the dynamic function is processed by inline, so the declaration of variable i is identified from line 8 to line 4 in the code. Because the return value interface {} of the dynamic function is a dynamic type, the actual use space of the dynamic type is determined at different compile times, so i is allocated to heap.
Closure escape
code
3 func main() { 4 f := fibonacci() 5 for i := 0; i < 10; i++ { 6 f() 7 } 8 } 9 10 func fibonacci() func() int { 11 a, b := 0, 1 12 return func() int { 13 a, b = b, a+b 14 return a 15 } 16 }
compile
% go build -gcflags "-m" ./main.go:12:12: can inline fibonacci.func1 ./main.go:11:5: moved to heap: a ./main.go:11:8: moved to heap: b ./main.go:12:12: func literal escapes to heap
explain
Not only the variables a and b escape, but also the return value function object is allocated to the heap
reference
https://www.jianshu.com/p/dcd87431a8af
https://segmentfault.com/a/1190000020086727?utm_source=sf-similar-article
https://zhuanlan.zhihu.com/p/113643434