SoFunction
Updated on 2025-03-05

GoLang escape analysis explanation

concept

When an object's pointer is referenced by multiple methods or threads, it is called escape analysis. Escape analysis determines whether a variable is allocated on the heap or on the stack. Of course, whether escape occurs is determined by the compiler.

Issues of allocating variables on stack and heap

1. Local variables are on the stack (statically allocated). After the function is executed, they are automatically recycled by the stack, resulting in painc null pointer exceptions for other references to this variable. The user-state of the stack implements goroutine as the execution context

2. Allocate variables in new on the heap (dynamic allocation). There is a feature on the heap. Variables will not be deleted, but will cause memory exceptions.

// The following code causes the program to crash, and the call stack obtains dangerous hanging pointersint *foo ( void)   
{     
int t = 3;
return &t;
} 

1. Benefits of allocating memory on the stack: General stack memory 2-4 MB
a. Fast recycling: Reduce GC pressure when the function returns to recover resources. No mark clearing required
b. Allocation fast stack allocation is faster than heap and there will be no memory fragmentation
c. Concurrency fast, clear synchronization. If there is a synchronization lock on the definition object, but only one thread accesses it, escape to analyze the machine code and remove the synchronization lock.

Summary: Escape analysis objective: Use the stack to allocate memory as much as possible go build -gcflags '-m -N -l' method to compile the escape analysis results

Escape analysis criteria

If a function returns a reference to a variable, then it escapes

  • There is no reference outside the function, and it is allocated to the stack first (pointer to the stack object cannot exist in the heap)--This pointer points to an invalid value or an incorrect memory value
  • There is a reference outside the function and must be allocated to the heap (pointer to the stack object cannot survive after the stack object is recycled - the memory pointed to is illegal)

CCN_ProLang/CoreGo/GoreGo There are corresponding documentation references below

General idea of ​​escape analysis

1. The most important function

$GOROOT/src/cmd/compile/internal/gc/

1. First build a directed acyclic graph weighted graph, vertices (variables assigned by statements and expressions), and edges (representing the assignment relationship between variables)
2. Iterate through the directed weighted graph, and the assignment paths that violate the above two unchanged conditions in the figure. The algorithm also records the data stream of each function's parameters to the heap and the data stream of its return value.
Weight

// p =&q -1 // Minimum value
// p =q 0
// p = *q // Dereference 1
// p = **q 2

Example: root =&L , the pointer of the L node points to root, so root has an edge, src is L, and the weight is -1

3. Escape analysis: Analysis: Allocation of memory and use Whether escape occurs
4. go build -gcflags = "-m -m -m -m -W -W -N -l"

1. When a variable in the function returns a value, it will not be possible to allocate it on the stack.

2. Most of the variables that are reassigned in the loop are allocated on the heap.

3. After the assignment of variables declared outside the closure is invalid, they need to be allocated on the heap.

Whether an escape occurs is determined by the compiler. Cause consequences: 1. Frequent GC leads to high CPU pressure 2. Causes large performance degradation

1. Some escape cases:
2. Function returns variable address Causes escape
func GetUserInfo(userInfo UserData) *UserData{
   // The compiler determines that external use has escaped, and the incoming parameter object is similar to copying a copy	return &userInfo
}
//Modify Change the input parameter to a pointer, there is no new structure in the middle and no escape occurs.func GetUserInfo(userInfo *UserData) *UserData {
		return userInfo
}
Case 2:Uncertain type escape
func MyPrintLn(one interface{}) (n int, err error){
	var userInfo = new(User)
	 = one // Generic assignment escapes Escape occurs during type conversion	return
}
Variables determine specific types
Example Three: Indirect variable assignment Closure
var {
     UserOne User // Value object     userTwo = new(User) // Reference object}
 = "one" // Don't escape = "two" // Escape = new(int) // Don't escape = new(int) // Escape The reference object is referenced and can only be allocated on the heap.Reference object: Compiler analyzer firstuserTwo Objects assigned to the heap,Member variablesname,age Reference Type,Guaranteed not to appear on the stack Cause the objectuserTwo Being recycled all name,age Need to escape
Optimization suggestions: 不要将Reference object赋值给Reference object

Summarize

There will definitely be no escape:

1. The pointer is referenced by a variable that does not escape

2. Only when the function is fetched on the variable, the pointer is not passed out.

Must escape

The pointer variable returned by the constructor new/make must escape

2. If the pointer is referenced by the escaped pointer variable, the escape will definitely occur.

3. The pointer type is slice, map, chan. The pointer reference must escape.

Maybe escape

Pass the pointer as an incoming parameter to another function. Here we look at the processing process of the pointer being passed into the function. If the above three situations occur, it will escape, otherwise it will not.

This is the end of this article about GoLang's escape analysis and explanation. For more related GoEscape content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!