Walk through the phases of a GC cycle. Where are the stop-the-world pauses?
Question 338HardGo 1.22 to 1.25
- Sweep termination (STW, microseconds): finish sweeping the previous cycle, reach a safe point on every P, and enable the write barrier.
- Concurrent mark: the world restarts. Dedicated background workers take about 25% of GOMAXPROCS. Idle Ps help, and allocating goroutines do mark assists. Each goroutine stack is scanned by briefly stopping only that goroutine.
- Mark termination (STW, microseconds): drain the remaining work, disable the write barrier, and compute the next heap goal.
- Concurrent sweep: spans are swept lazily when allocation needs them, plus by a background sweeper.
Since goroutine preemption became asynchronous (signal-based, Go 1.14), a tight loop with no function calls can no longer hold up a STW for a long time.
Where latency really comes from: usually not the STW pauses but mark assists. An allocation-heavy request goroutine can be made to do GC work, which inflates its tail latency. The GC also takes 25% or more of the CPU while it is marking. In GODEBUG=gctrace=1 output, check the assist share of the mark CPU time.
What the interviewer is looking for: the two short pauses, that everything else is concurrent, and that the real cost is CPU and assists rather than pause time.
More on Memory, GC & Runtime Internals
- Q336Explain Go's concurrent tri-color mark-and-sweep garbage collector.
- Q337What is a write barrier and which one does Go use?
- Q339Is Go's GC generational or compacting? What is the "Green Tea" GC?
- Q340What does GOGC control, exactly? What happens with GOGC=off, 50 or 200?
- Q341What is GOMEMLIMIT and how would you set it in a container?
- Q342How do you read a line of
GODEBUG=gctrace=1output?