📜 ⬆️ ⬇️

Garbage collector in Go: solving the problem of responsiveness in Go 1.5

This material is a translation of a blog post in real time by the guys from Sourcegraph from the GopherCon 2015 conference, which takes place these days in Denver, Colorado. Full video and slides of the report will be added to the post as soon as they are available.

Richard L. Hudson (Rick) is famous for his work in memory management, including the invention of the Train, Sapphire and Mississippi Delta algorithms, as well as GC stack maps, which allowed for garbage collection in statically-typed languages ​​like Java, C # and Go. Under his authorship were published documents about runtimes of languages, memory management, multithreading, synchronization, memory models and transactional memory. Rick is now a member of the Go team at Google and is working on the problems of the garbage collector and runtime.



')
In economics, there is the concept of "closed loop", when one process strengthens another, which leads to the strengthening of the first. Historically, in the computer world, such a “closed loop” was between the development of hardware and software. The processors became faster, which contributed to the writing of more powerful software, which, in turn, stimulated a further increase in the speed of the processors and the power of the computer as a whole. This cycle worked until about 2004, when Moore's Law stopped working.



Nowadays, a twofold increase in the number of transistors does not mean a twofold acceleration of programs. More transistors == more processor cores, but the programs did not evolve enough to use more cores. And precisely because modern programs do not use multi-core to the fullest, the guys developing processors simply do not add more cores. The loop is dead.

Go's long-term mission is to restart this cycle, giving the world more parallel, competitive programs. A more short-term mission is to increase acceptance of Go by the global developer community. And one of the biggest complaints about Go at the moment is that the garbage collector’s pauses are too long.

When their team initially took up the problem, he jokingly says that their initial reaction, as engineers, was not to solve the problem itself, but to find a workaround, something like this:





But Russ Cox, for some reason, flunked these ideas in the bud, and they decided to roll up their sleeves and actually improve the garbage collector at Go. They came up with an algorithm that reduces GC pauses, but makes the program a little slower. Go programs will become a bit slower in exchange for guaranteed low pauses of garbage collection phases.

What delays can we distinguish?


So how much garbage collection work can we have in one millisecond?

Java GC vs Go GC




Go:


Java:


The biggest difference here is the issue of spatial locality. In Java, everything is a pointer, but in Go you can embed structures one into another. When you have to follow links to many levels in depth, this can create a lot of problems for the garbage collector.

Garbage Collection Basics


Here is a brief example of how a garbage collector works. Usually, it consists of two phases:



  1. Scan Phase: Determine which items in the heap are reachable. This includes pointers to stacks, registers, global variables, and further pointers on the heap.
  2. Marking Phase: Pass through the pointer graph. Mark objects as achievable during the execution of the program. From the point of view of the garbage collector, the easiest way is to “stop the world” so that the pointers do not change during this phase at all. A really parallel garbage collector is very difficult to do, because pointers are constantly changing. The program uses so-called “write barriers” to write to the garbage collector that this object does not need to be captured. In practice, however, recording barriers can produce even worse results than “stopping the world”.


Garbage collector in Go


The new Go garbage collection algorithm uses a combination of write barriers and short pauses to “stop the world.” Here are its phases:



This is how the garbage collector in Go 1.4 looked like:



And this is how it looks in Go 1.5:



Notice that the pause for “stop the world” is much shorter. While running the parallel garbage collector, it uses 25% of the processor.

Here are the test results:



In previous versions of Go, garbage collector pauses were generally much longer and increased as the size of the heap grew. In Go 1.5, garbage collector pauses have become more than an order of magnitude smaller.

If you bring the numbers closer, you can see that there is still a weak positive correlation between the heap size and the duration of GC pauses. But they know the reason and it will be eliminated in Go 1.6.



There is a small performance penalty with the new algorithm, but this penalty decreases as the heap volume grows.



Looking to the future


Tell people that garbage collector pauses are no longer a problem in Go. Looking to the future, they plan to tinker up with the garbage collector to achieve even shorter pauses, more productivity and more predictability. They want to find the optimal ratio in this compromise. The development of Go 1.6 will depend on feedback, so they are very much waiting for feedback from the community.



The new garbage collector will make Go an even more suitable replacement for languages ​​with manual memory management.

Links


Slides: talks.golang.org/2015/go-gc.pdf

More about the garbage collector in Go


Go 1.5 concurrent garbage collector pacing
Go 1.4+ Garbage Collection (GC) Plan and Roadmap

Source: https://habr.com/ru/post/262335/


All Articles