Go study notes (75)-stack memory, heap memory, escape analysis

Transfer from:
https://kaiwu.lagou.com/course/courseInfo.htm?courseId=536#/detail/pc?id=5247

In order to allow programmers to better focus on the implementation of business code, the Golanguage adds a garbage collection mechanism to automatically reclaim memory that is no longer used. GoThe language has two parts of memory space: stack memory and heap memory.

1. Stack memory

The stack only allows to put data into one end of the linear table, and then take out the data at this end, in the order of LIFO (Last In First Out), as shown in the figure.
Stack memory
The process of putting elements on the stack is called pushing. Pushing the stack will increase the number of elements on the stack. The last element placed is always at the top of the stack, and the element placed first is always at the bottom of the stack.

When removing elements from the stack, they can only be removed from the top of the stack. After removing the elements, the number of stacks will be reduced. The element that is put in first is always taken out last, and the element that is put in last is always taken out first. It is not allowed to obtain data from the bottom of the stack, nor is it allowed to view or modify any members of the stack (members other than the top of the stack).

The stack memory is automatically allocated and released by the compiler, and the developer cannot control it. The stack memory generally stores local variables, parameters, etc. in the function. When the function is created, these memories are automatically created; when the function returns, these memories are automatically released.

The stack can be used for memory allocation, the allocation and recovery of the stack is very fast. The following code shows the role of branches in memory allocation, the code is as follows:

func calc(a, b int) int {
    
    
	var c int
	c = a * b

	var x int
	x = c * 10

	return x
}

The above code is optimized without any circumstances, will be performed c, and xassigned process variable. GoUnder language will default cand xallocated on the stack, these two variables calc()will no longer be used when the function exits, the end of the function, save cand xstack memory and then release the stack memory, the memory allocation process through the entire stack allocation and Recycling will be very fast.

2. Heap memory

Pile in memory allocation is similar to placing various furniture in a room, and the size of the furniture varies.

When allocating memory, you need to find a space enough to hold the furniture before placing the furniture. After repeatedly placing and emptying the furniture, the space in the room will become messy. At this time, placing furniture in the space will exist. Although there is enough space, the spaces are distributed in different areas, and there is no continuous space. Come to the problem of placing furniture.

At this time, the memory allocator needs to adjust and optimize these spaces, as shown in the figure.

Heap memoryCompared with the memory allocated by the heap and the memory allocated by the stack, the heap is suitable for memory allocation of unpredictable size. But the price paid for this is slower allocation speed and memory fragmentation.

The life cycle of heap memory is longer than stack memory. If the value returned by the function will be used elsewhere, then this value will be automatically allocated to the heap by the compiler. Compared with stack memory, heap memory cannot be automatically released by the compiler, and can only be released by the garbage collector, so the stack memory efficiency will be very high.

2. Escape analysis

Since stack memory is more efficient, stack memory must be used first. So Golanguage is how a judge should be assigned to the variable on the heap or stack it? This requires escape analysis. Below I use an example to explain escape analysis, the code is as follows:

package main

func main() {
    
    
    newString()
}

func newString() *string{
    
    
   s:=new(string)
   *s = "wohu"
   return s
}

Now I use escape analysis to see if an escape has occurred. The command is as follows:

wohu@ubuntu:~/gocode/src$ go build -gcflags="-m -l" demo.go
# command-line-arguments
./demo.go:12:10: new(string) escapes to heap
wohu@ubuntu:~/gocode/src$ 
  • -m Means to print out the escape analysis information;
  • -l Indicates that inlining is prohibited, and escape can be better observed;

It can be seen from the above output that an escape has occurred, which means that when a pointer is used as a function return value, an escape must occur.

Variables that escape to the heap memory cannot be recycled immediately. They can only be cleared by garbage collection marks, which increases the pressure of garbage collection. Therefore, avoid escaping as much as possible and allocate variables on the stack memory so that resources can be recycled when the function returns. ,Improve efficiency.

Here I newStringfunction has been optimized to avoid the escape function optimized code as follows:

func newString() string{
    
    
   s:=new(string)
   *s = "wohu"
   return *s
}

View the escape analysis of the above code through the command again, the command is as follows:

wohu@ubuntu:~/gocode/src$ go build -gcflags="-m -l" demo.go
# command-line-arguments
./demo.go:8:10: newString new(string) does not escape
wohu@ubuntu:~/gocode/src$ 

Through the analysis results, we can see that although the pointer variable is still declared s, the function returns not the pointer, so no escape occurs.

Escape analysis is a method of judging whether variables are allocated on the heap or on the stack. In actual projects, escape should be avoided as much as possible, so as not to be slowed down by the GC, thereby improving efficiency.

Tips: From the point of view of escape analysis, although pointers can reduce memory copying, they can also cause escapes, so you should choose whether to use pointers according to the actual situation.

Optimization skills

  • Avoid escapes as much as possible, because the stack memory is more efficient, so it's not needed GC. For example, parameter passing small objects, arraybetter than slicegood effect.

  • If escaping cannot be avoided, and memory is allocated on the heap, then for frequent memory application operations, we must learn to reuse memory, such as use sync.Pool.

  • Choose appropriate algorithms to achieve high performance, such as space for time.

Tips: When optimizing performance, you must combine benchmark tests to verify whether your optimization has improved.

The above is based on Goskill summed up the language of memory management mechanism in three directions, based on these three general direction basically can optimize the effect you want. In addition, there are some tips to avoid as much as possible such as using locks, concurrency locked narrowly as possible, use StringBuildermake stringand [ ] byteconversion between, defernesting not too much more.

The last recommended a Gotool that comes with the performance analysis of language pprof, through which you can view the CPUanalysis, memory analysis, obstruction analysis, mutex analysis.

Guess you like

Origin blog.csdn.net/wohu1104/article/details/113815428