Optimizing code for better results in the golang GC seems to be more of a rather important thing recently with the strongly time-optimized GC runs. I was recently told how much it accomplishes in a run "depends on your pattern of heap memory usage.", but I'm not really sure exactly what that means/entails from the perspective of a programmer in the language. Or is that not something that can easily be controlled?
I have read through the recent book "The Go Programming Language" by Brian W. Kernighan, but there is nothing about this topic in it. And all information on this topic on the internet are from years ago, so don't really apply.
Some things I currently do include:
I am also a bit annoyed by the fact that strings and byte arrays are always recreated when converting between one or the other (due to strings being immutable). So when I am going from one to the other, and its a safe operation, I just recast their pointers to the other type using unsafe.
Are all of these practices worth it to help the GC run faster and clear more? Is there anything else I could do?
Garbage collection is a mechanism Go developers use to find memory space that is allocated recently but is no longer needed, hence the need to deallocate them to create a clean slate so that further allocation can be done on the same space or so that memory can be reused.
Go has all goroutines reach a garbage collection safe point with a process called stop the world. This temporarily stops the program from running and turns a write barrier on to maintain data integrity on the heap. This allows for concurrency by allowing goroutines and the collector to run simultaneously.
The Go developers probably observed that starting a GC approximately every two minutes was a reasonable trade-off between the overhead of a GC cycle and memory used.
The GOGC variable sets the initial garbage collection target percentage. A collection is triggered when the ratio of freshly allocated data to live data remaining after the previous collection reaches this percentage. The default is GOGC=100. Setting GOGC=off disables the garbage collector entirely.
If it were a simple matter of a list of do's and don'ts we could simply write a program to optimize memory usage.
The first step is to write correct, well-designed, maintainable, and easy-to-read code.
Next, using Go's testing package, benchmark critical functions. For example. a real case,
BenchmarkOriginal 30000 44349 ns/op 52792 B/op 569 allocs/op
Use Go's profile tool. Read the source and executable code to see what is going on.
Implement strategies, such a single underlying array and full slice expressions, to reduce GC memory allocations and CPU time. Run a final benchmark.
BenchmarkOptimized 100000 13198 ns/op 32992 B/op 3 allocs/op
In this case, 569 allocations of the elements of a triangular array were reduced to 3 allocations, a 99% reduction in allocations with a corresponding 70% reduction in CPU time. There's a lot less for the garbage collector (GC) to do too.
Of course, this made the code harder to read (more complex and more obscure) and thus harder to maintain.
Don't over optimize. Do you really have nothing better to do? The best optimization is often buying a bigger computer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With