Ein 40-Millisekunden-Stillstand im Go-Garbage-Collector – verursacht durch Swap

A 40ms Go garbage collector pause caused by swap

Ein 40-Millisekunden-Stillstand im Go-Garbage-Collector – verursacht durch Swap

Ein Go-Prozess mit io.ReadAll und proto.Unmarshal erzeugte unter Speicherdruck 40ms lange Stop-the-World-Pausen, weil der GC seine Metadaten liest und diese durch das Kernel-Swapping auf die NVMe ausgelagert wurden. 228 Page Faults verursachten 39 der 40ms. Zusätzlich stieg der Aufbau einer 511-KiB-Nachricht von 3–5ms auf bis zu 903ms. Der Green Tea GC von Go 1.26 änderte daran nichts.

Ich habe das gemessen, und der Effekt ist vernachlässigbar.
  1. nasretdinov

    Leider ist das einigermaßen zu erwarten – unabhängig von der Implementierung macht allein die Tatsache, dass der GC irgendwie den gesamten Baum durchlaufen muss, um noch referenzierte Bereiche zu verfolgen, Swap höchst unpraktisch – selbst wenn man keine 40-ms-Stop-the-World-Pausen hätte, würde der von Swap verwendete LRU-Cache bei jeder GC-Sammlung verworfen.

    Ich glaube, das ist tatsächlich derselbe Grund, warum Apple aufgehört hat, GC in seinen Frameworks zu verwenden, und stattdessen auf automatische Referenzzählung setzt.

  2. jacobgold

    "Es tut weh, wenn ich das mache."

    "Dann lass es."

    Wenn dir Latenz wichtig ist, deaktiviere Swap. Systemweit oder für das spezifische cgroup.

  3. pizlonator

    Gibt es einen Grund, warum Go nicht On-the-fly-GC verwendet, bei der es überhaupt keine STW-Pausen gibt?

  4. xavdid

    Discord hat das bereits 2020 gelernt und einen großartigen Blogbeitrag darüber veröffentlicht: https://discord.com/blog/why-discord-is-switching-from-go-to...

  5. soltanov

    Ein GC-Latenz-SLO sollte den Speicherdruck des Betriebssystems einschließen. Andernfalls sieht ein Page-Fault-Problem wie ein Collector-Problem aus und führt zur falschen Lösung.

  6. Gabrys1

    Ich habe mich gefragt, ob es einen swap-bewussten GC geben könnte, der zuerst die benötigte Seite einswap-t (nicht dass es dafür eine offensichtliche API gäbe ...) und erst dann die Welt anhält?

  7. imclaren

    Dies. Memory-Bloat-Bugs sind in Go relativ einfach zu beheben, aber manchmal ist es ein Abenteuer, Swap-Bloat zu beseitigen. Und ich denke, es lohnt sich, allen Swap-Bloat zu beseitigen!

  8. faangguyindia

    Ich verwende Go, wo ich Node, Ruby oder Python verwenden würde.

    Ich verwende Rust, wo ich niedrige Latenz brauche.

Mehr von diesem Tag

2026-10-05