From the perspective of memory allocation strategy (heap, stack), is passing Pointers really more efficient than passing values?
Keep updating on my Github and welcome Star
introduce
For beginners, many students must be entangled in:
- Does the function pass Pointers or values?
- What is the essential difference between the two options?
- Which has better performance?
Analysis of the
Finding the difference certainly takes some work, and that’s what Golang’s implementation is all about. First of all, one of the most important concepts in Golang is Escape analysis, where the compiler decides where to allocate memory.
- Allocated on the stack, memory is automatically reclaimed at the end of the function
- Allocated in the heap, the end of the function can be handed over to the GC (garbage collection)
In the end, the execution efficiency of the program is significantly related to these two allocation rules. The main difference between value passing and pointer passing lies in whether the underlying value needs to be copied. On the surface, pointer passing does not involve value copying, so the efficiency is definitely higher. However, the actual situation is that pin passing will involve variables escaping to the heap and will increase the burden of GC, so what we want to do in this paper is to carry out escape analysis and make a conclusion first according to the convention.
- Allocating memory on the stack is more efficient than allocating memory in the heap
- Memory allocated on the stack does not need GC and is automatically reclaimed after the function is executed
- Memory allocated on the heap is handed over to the GC when it is used
- When an escape occurs, requested memory on the stack is moved to the heap
- Pointers can reduce the copying of underlying values, which can improve efficiency, but can cause escape, but if the amount of data copied is small, the burden of escape (heap memory allocation +GC collection) can reduce efficiency
- Therefore, the size of a variable is a very important analysis indicator when choosing between value passing and pointer passing
Each approach has its own advantages and disadvantages. Values on the stack reduce the pressure on the GC, but Pointers on the heap increase the pressure on the GC to maintain multiple copies, but only one value is maintained. So choose which way, according to their own business situation reference this standard to choose.
Let’s do a little bit of code first
// escape.go
package main
type person struct {
name string
age int
}
func main(a) {
makePerson(32."Emma Stone")
showPerson(33."Yang")}func makePerson(age int, name string) *person {
maliya := person{name, age}
return &maliya
}
func showPerson(age int, name string) person {
yangmi := person{name, age}
return yangmi
}
Copy the code
Run the following command to perform escape analysis
go build -gcflags="-m -m -l" escape.go
Copy the code
Output result:
Escape/Escape.go:15:9: &maliya escapes to heap
Escape/Escape.go:15:9: from ~r2 (return) at Escape/Escape.go:15:2
Escape/Escape.go:14:2: moved to heap: maliya
Escape/Escape.go:13:40: leaking param: name to result ~r2 level=-1
Escape/Escape.go:13:40: from person literal (struct literal element) at Escape/Escape.go:14:18
Escape/Escape.go:13:40: from maliya (assigned) at Escape/Escape.go:14:9
Escape/Escape.go:13:40: from &maliya (address-of) at Escape/Escape.go:15:9
Escape/Escape.go:13:40: from ~r2 (return) at Escape/Escape.go:15:2
Escape/Escape.go:18:39: leaking param: name to result ~r2 level=0
Escape/Escape.go:18:39: from person literal (struct literal element) at Escape/Escape.go:19:18
Escape/Escape.go:18:39: from yangmi (assigned) at Escape/Escape.go:19:9
Escape/Escape.go:18:39: from ~r2 (return) at Escape/Escape.go:20:2
Copy the code
From the results, we can see that the variable & Maliya escaped, but the variable Yangmi did not escape
&maliya escapes to heap from ~r2 (return) at Escape/Escape.go:15:2
moved to heap: maliya
Copy the code
So makePerson returns a pointer type that has escaped, and showPerson returns a value type that has not escaped.
There are many other cases of variable escape, and there are many analysis articles on the Internet. Instead of giving examples, the conclusion is given directly:
- When a value on the stack is shared, it escapes
- Run out of stack space (e.g. create a large slice that exceeds the stack space)
- Dynamic type escape with function parameters of type interface (typical fmt.println method)
- The closure reference object escapes, essentially sharing values on the stack