Dev Genius

Coding, Tutorials, News, UX, UI and much more related to development

Follow publication

Golang Memory Escape In-Depth Analysis

--

You must master the Golang memory escape knowledge points

Photo by Alesia Kazantceva on Unsplash

Recently a friend is learning Golang, he said he encountered a problem, the following code actually does not report an error, and his experience in writing C language, this code should not be compiled.

This code is really no problem for Golang, let’s look at the C code below.

When we execute gcc demo.c there will be return a warning.

demo.c:6:13: warning: address of stack memory associated with local variable 'data' returned [-Wreturn-stack-address]return &data;1 warning generated.

The prompt says that a stack memory is returned, which is not allowed. My friend is curious why this behavior is allowed in Golang, which leads to the problem we are going to analyze today: Golang’s memory escape behavior.

Memory in a program is divided into two areas, one for the stack and one for the heap. The stack area has a specific structure and addressing method, and is very fast to address with little overhead. The heap, on the other hand, is an area of memory that has no specific structure and no fixed size and can be adjusted as needed.

Global variables, local variables with a large memory footprint, and local variables that cannot be reclaimed immediately after a function call are all stored inside the heap. Variables are allocated and reclaimed on the heap with much more overhead than on the stack.

In simple terms, the memory requested inside a function call is stored on the stack, and this memory is immediately returned to the system at the end of the function.

In the above example, the variable data applied inside the function will be recycled after the function ends and will not persist. They are all stored in the stack area. Because the existence time is short and the stack area allocation speed is fast, the compiler will confirm that this is the best choice.

Let’s look at another example.

In the above example, the variable data will not be released after the function ends, because the pointer to the variable is returned, the compiler will think that the variable is used elsewhere after the function ends, so it will keep this memory, At the same time, apply to the heap, because the memory in the heap will not be reclaimed immediately, and the memory in the stack will be reclaimed immediately.

We use go tool compile -m to analyze the initial code:

$ go tool compile -m demo.godemo.go:3:6: can inline demoFunctiondemo.go:8:6: can inline maindemo.go:9:31: inlining call to demoFunctiondemo.go:4:9: moved to heap: data

According to the analysis results, we can see that moved to heap: dataindicates that the datathe variable has escaped to the heap memory.

There is a note about variable assignment issues on the Golang official website FAQ:

From a correctness standpoint, you don’t need to know. Each variable in Go exists as long as there are references to it. The storage location chosen by the implementation is irrelevant to the semantics of the language.

The storage location does have an effect on writing efficient programs. When possible, the Go compilers will allocate variables that are local to a function in that function’s stack frame.

However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors. Also, if a local variable is very large, it might make more sense to store it on the heap rather than the stack.

In the current compilers, if a variable has its address taken, that variable is a candidate for allocation on the heap. However, a basic escape analysis recognizes some cases when such variables will not live past the return from the function and can reside on the stack.

To summarize: if a variable is taken address, then it may be allocated on the heap. However, these can only be confirmed after the escape analysis operation is performed on the variable. If the variable is no longer referenced after the function returns, it will be allocated to the stack.

Let’s take a look at the scenarios of memory escape.

1. Pointer escape

The variable p is a local variable, but because it is returned by reference, it will escape to the heap memory. View the compilation analysis as follows:

$ go tool compile -m person.goperson.go:7:6: can inline SetPersonperson.go:13:6: can inline mainperson.go:14:11: inlining call to SetPersonperson.go:7:16: leaking param: nameperson.go:8:10: new(Person) escapes to heap // [Escape happens here]person.go:14:11: new(Person) does not escape

2. Insufficient stack space to escape

The analysis is performed as follows:

$ go tool compile -m index.goindex.go:4:11: make([]int, 10000, 10000) escapes to heap

3. Dynamic type escape

There are many functions whose parameter type is interfacetype, which is difficult to determine the specific type of the parameter at compile-time, and this type of case will also generate escapes. For example the built-in function Printlnmethod.

The analysis is performed as follows:

$ go tool compile -m hello.gohello.go:5:6: can inline mainhello.go:6:13: inlining call to fmt.Printlnhello.go:6:14: "hello golang" escapes to heap // [Escape happens here]hello.go:6:13: []interface {}{...} does not escape<autogenerated>:1: leaking param content: .this

There will be memory escape analysis when the program is compiled, and memory escape analysis has 2 benefits:

  • After escape analysis, it can be confirmed whether specific variables are allocated in heap memory or stack memory, which improves program performance.
  • Reduce GC pressure, and variables that do not escape can be recycled in time.

Final summary:

  • For small data, use pass-by-value instead of pointer
  • Avoid sliceof indeterminate length for hot data
  • Avoid passing parameters to interface, try to use explicit types
  • The allocation of variables is confirmed after escape analysis. Golang officially identifies all this so that developers can focus on the business logic itself without paying too much attention to memory.

Thanks for reading this, and if you find any errors in the article, please feel free to leave a comment.

Have a nice day.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Published in Dev Genius

Coding, Tutorials, News, UX, UI and much more related to development

Written by Dwen

I'm an independent entrepreneur, a developer and a father, enjoys speaking, writing, and sharing.

Responses (2)

Write a response