How to minimize the garbage collection in Go?

2019-03-08 11:23发布

问题:

Some times you could want to avoid/minimize the garbage collector, so I want to be sure about how to do it.

I think that the next one is correct:

  • Declare variables at the beginning of the function.
  • To use array instead of slice.

Any more?

回答1:

Avoiding garbage is relatively straight forward. You need to understand where the allocations are being made and see if you can avoid the allocation.

First, declaring variables at the beginning of a function will NOT help. The compiler does not know the difference. However, human's will know the difference and it will annoy them.

Use of an array instead of a slice will work, but that is because arrays (unless dereferenced) are put on the stack. Arrays have other issues such as the fact that they are passed by value (copied) between functions. Anything on the stack is "not garbage" since it will be freed when the function returns. Any pointer or slice that may escape the function is put on the heap which the garbage collector must deal with at some point.

The best thing you can do is avoid allocation. When you are done with large bits of data which you don't need, reuse them. This is the method used in the profiling tutorial on the Go blog. I suggest reading it.

Another example besides the one in the profiling tutorial: Lets say you have an slice of type []int named xs. You continually append to the []int until you reach a condition and then you reset it so you can start over. If you do xs = nil, you are now declaring the underlying array of the slice as garbage to be collected. Append will then reallocate xs the next time you use it. If instead you do xs = xs[:0], you are still resetting it but keeping the old array.

For the most part, trying to avoid creating garbage is premature optimization. For most of your code it does not matter. But you may find every once in a while a function which is called a great many times that allocates a lot each time it is run. Or a loop where you reallocate instead of reusing. I would wait until you see the bottle neck before going overboard.



回答2:

To minimize garbage collection in Go, you must minimize heap allocations. To minimize heap allocations, you must understand when allocations happen.

The following things always cause allocations (at least in the gc compiler as of Go 1):

  • Using the new built-in function
  • Using the make built-in function (except in a few unlikely corner cases)
  • Composite literals when the value type is a slice, map, or a struct with the & operator
  • Putting a value larger than a machine word into an interface. (For example, strings, slices, and some structs are larger than a machine word.)
  • Converting between string, []byte, and []rune
    • As of Go 1.3, the compiler special cases this expression to not allocate: m[string(b)], where m is a map and b is a []byte
  • Converting a non-constant integer value to a string
  • defer statements
  • go statements
  • Function literals that capture local variables

The following things can cause allocations, depending on the details:

  • Taking the address of a variable. Note that addresses can be taken implicitly. For example a.b() might take the address of a if a isn't a pointer and the b method has a pointer receiver type.
  • Using the append built-in function
  • Calling a variadic function or method
  • Slicing an array
  • Adding an element to a map

The list is intended to be complete and I'm reasonably confident in it, but am happy to consider additions or corrections.

If you're uncertain of where your allocations are happening, you can always profile as others suggested or look at the assembly produced by the compiler.