The problem
A quick word on Golang’s memory escape?
parsing
What is memory escape
In the program, each function block will have its own memory area to store its local variables (less memory), return address, return value and other data, this piece of memory area has a specific structure and addressing mode, addressing is very fast, low cost. This block of memory is called the stack. Stacks are thread-level, their size is determined at creation time, and when variables become too large, they “escape” onto the heap, a phenomenon known as memory escape. In simple terms, local variables are allocated and reclaimed by the heap, which is called memory escape.
Memory escape hazards
A heap is an area of memory with no specific structure and no fixed size that can be adjusted as needed. Global variables, local variables that have a large memory footprint, and local variables that cannot be reclaimed immediately after a function call are stored in the heap. The allocation and collection of variables on the heap are much more expensive than on the stack. For a GC language like GO, this can increase GC stress and cause memory fragmentation.
How to analyze if a program has memory escape
/main.go:3:6: Moved to heap: x Indicates that the local variable X escaped to the heap.
When memory escape occurs
- to
channel
Send pointer data. Because you don’t know at compile time which Goroutine will receive the data in a channel, the compiler has no way of knowing when the variable will be released, so it has to be put in the heap.
package main
func main(a) {
ch := make(chan int.1)
x := 5
ch <- x // x does not escape because it is just the copied value
ch1 := make(chan *int.1)
y := 5
py := &y
ch1 <- py // the y address is passed into chan, and the compiler cannot determine when it will be received, so it cannot reclaim y after the function returns
}
Copy the code
- Local variables are used elsewhere after a function call, such as when a function returns a pointer to a local variable or a value referenced outside a closure. Because variables may outlive functions, they can only be placed in the heap.
package main
func Foo (a) func (a){
x := 5 // x escapes because after Foo is called, it is used by the closure and cannot be reclaimed. It can only be stored on the heap
return func (a) {
x += 1}}func main(a) {
inner := Foo()
inner()
}
Copy the code
- Store Pointers in slice or map. For example, []*string, the array behind it might be allocated on the stack, but the values it references are still on the heap.
package main
func main(a) {
var x int
x = 10
var ls []*int
ls = append(ls, &x) // when x escapes, ls stores Pointers, so the underlying array of LS is stored on the stack, but x itself escapes onto the heap
}
Copy the code
- After the slice is expanded, its length is too large, resulting in insufficient stack space and escape to the heap.
package main
func main(a) {
s := make([]int.10000.10000)
for index, _ := range s {
s[index] = index
}
}
Copy the code
- Call a method on the interface type. The interface variable is heap-allocated when a method is called on the interface type, because the true implementation of the method is known only at run time.
package main
type foo interface {
fooFunc()
}
type foo1 struct{}
func (f1 foo1) fooFunc(a) {}
func main(a) {
var f foo
f = foo1{}
f.fooFunc() // When a method is called, f escapes because the method is allocated dynamically
}
Copy the code
A way to avoid memory escape
- For small data, use pass values instead of Pointers to avoid memory escape.
- Avoid using slice slices of variable length, which cannot be determined at compile time and can only be heap-allocated.
- Interface call methods can escape memory, use with caution in hot snippets.
Write in the last
If you like this article, welcome to pay attention to the public account “will play code”, focus on plain English to share practical technology.
Welfare of public account
Mysql > get free test database!!
Reply [PDF] get continuous update massive learning materials!!