How does go know whether an object is allocated on the stack or the heap?

How to judge whether the variable is allocated on the stack (stack) or on the heap (heap)?

Go is different from C++, Go local variables will undergo escape analysis . If the variable is not referenced after leaving the scope , it is allocated on the stack first , otherwise it is allocated on the heap. Judge sentences:

// -m打印逃逸分析信息, -l禁止内联编译
go build -gcflags '-m -m -l' xxx.go 

usually:

On the stack : Most of the parameters, return values, and small-type local variables of function calls are allocated on the stack, and this part of memory will be managed by the compiler. No need for GC marking

On the heap : Large objects and escaped variables will be allocated on the heap. For objects allocated on the heap, the GC will mark the corresponding memory in the background when Go is running , so that the corresponding memory can be reclaimed during garbage collection, which increases the overhead .

example:

 

func main() {
	a := make([]int, 10000)
	b := make([]int, 1000)
    print(a,b)
}

can be seen

a Since it cannot be installed in an execution stack, even if it does not return, it will be directly allocated on the heap;
b can be installed in an execution stack, the variable does not return to the stack, and thus does not escape, and is allocated to the stack

 


Pointer Escape Analysis

Local variables are passed from methods in the form of pointers or referenced by global variables . This phenomenon is called pointer escape (Escape).

Case 1 (the most basic): If a variable created by new or a literal value is used in a function , and its pointer is used as the return value of the function , the variable must escape

func main() {
	c := call2()
    print(c)
}
func call2() *int {
	x := 2
	return &x
}

Case 2: If the pointer is used as a function call parameter , if the variable is not referenced by an escaped variable or a global variable , the pointer will not escape .

func main() {
	a := make([]int, 5)
	call(&a)
}

func call(a *[]int) {
	(*a)[0] = 1
}

 Case 3: The variable is only valued in the function , but the pointer is not passed out , and the pointer will not escape

 

func main() {
	a := 2
	b := &a
    print(b)

Situation 4: If the pointer is used as a function call parameter , if the variable is referenced by an escaped variable or a global variable , the pointer will escape

var g *int

func main() {
	a := 2
	g = &a
}

 Situation 5: Pointers referenced by slices, maps, and chans of pointer types must escape

func main() {
	a := make([]*int, 1)
	b := 12
	a[0] = &b

	c := make(map[string]*int)
	d := 14
	c["aaa"] = &d

	e := make(chan *int, 1)
	f := 15
	e <- &f
}

 


Summarize

Whether golang variables are stored on the heap or on the stack is determined by the internal implementation and has nothing to do with the specific syntax. Small non-pointer objects are usually stored on the stack, and large objects are stored on the heap. As for whether the pointer is stored on the heap or on the stack, escape analysis is required:

There are three situations in which the pointer must escape :

  • In a function, if a variable created by new or literal is used as the return value of the function, the variable must escape (the pointer variable returned by the constructor must escape);
  • A pointer referenced by a variable that has escaped must escape;
  • Pointers referenced by pointer-type slices, maps, and chan must escape;

Some cases that are bound not to escape :

  • The pointer is referenced by a variable that has not escaped;
  • Only take the address of the variable within the function, without passing the pointer out;

Guess you like

Origin blog.csdn.net/qq_48626761/article/details/132030161