1 Punkte von GN⁺ 2026-01-11 | 1 Kommentare | Auf WhatsApp teilen
  • Im Ghostty-Terminalemulator wurde ein schwerwiegendes Speicherleck entdeckt, bei dem bei langem Betrieb mehrere Dutzend GB Speicher belegt werden konnten
  • Ursache des Problems war, dass in der nicht standardmäßigen Wiederverwendungslogik für Speicherseiten der PageList-Struktur munmap nicht aufgerufen wurde und sich dadurch nicht freigegebener Speicher ansammelte
  • Weil Claude Code CLI häufig Graph-Ausgaben mit mehreren Codepoints erzeugt, stieg die Nutzung nicht standardmäßiger Seiten stark an, wodurch das Leck in großem Maßstab sichtbar wurde
  • Der Fix wurde so umgesetzt, dass nicht standardmäßige Seiten nicht wiederverwendet, sondern sofort freigegeben werden; zur Nachverfolgung und Verifizierung des Lecks wurde außerdem die VM-Tag-Funktion von macOS genutzt
  • Der Fix gilt als Behebung des größten Leck-Problems in Ghostty und soll in ein kommendes Release (1.3) aufgenommen werden

Überblick über das Speicherleck in Ghostty

  • Einige Nutzer berichteten, dass Ghostty nach langem Betrieb mehr als 37 GB Speicher verwendete
    • Das Leck existierte mindestens seit Version 1.0, und erst neuere CLI-Apps erfüllten bestimmte Bedingungen, durch die das Problem sichtbar wurde
  • Die Korrektur wurde bereits auf GitHub zusammengeführt und soll in Nightly-Builds sowie im offiziellen Release 1.3 enthalten sein

Aufbau der PageList und Speicherverwaltung

  • Ghostty verwendet zum Speichern des Terminalinhalts eine doppelt verkettete Listenstruktur namens PageList
    • Jede Seite enthält Daten wie Zeichen, Styles und Hyperlinks
  • Seiten werden mit mmap allokiert und über einen Pool für Seiten in Standardgröße wiederverwendet
    • Seiten bis zur Standardgröße werden an den Pool zurückgegeben
    • Seiten mit nicht standardmäßiger Größe müssen direkt mit munmap freigegeben werden
  • Die Struktur selbst ist korrekt, doch ein Bug in der Optimierungslogik führte zum Leck

Scrollback-Optimierung und Ursache des Bugs

  • Wenn Ghostty das scrollback-limit überschreitet, wird eine Optimierung ausgeführt, bei der die älteste Seite wiederverwendet wird
    • Dadurch steigt die Performance, weil keine neue Seite allokiert und nur Pointer angepasst werden müssen
  • Das Problem war, dass dabei nur die Metadaten einer nicht standardmäßigen Seite auf Standardgröße geändert wurden, während der tatsächliche Speicher unverändert blieb
    • Bei der späteren Freigabe wurde sie dadurch fälschlich als Standardseite behandelt, sodass munmap nicht aufgerufen wurde
  • Infolgedessen wurden nicht standardmäßige Seiten nicht freigegeben und sammelten sich an, was bei langer Laufzeit zu einem massiven Speicherleck führte

Claude Code und das großflächige Sichtbarwerden des Lecks

  • Claude Code CLI erzeugt häufig Graph-Ausgaben mit mehreren Codepoints, wodurch die Nutzung nicht standardmäßiger Seiten zunimmt
    • Zudem entsteht viel Scrollback-Ausgabe, sodass sich das Leck schnell ansammelt
  • Nach dem Design von Ghostty sollten nicht standardmäßige Seiten nur selten auftreten, doch durch die Eigenschaften von Claude Code ließ sich das Leck in großem Umfang reproduzieren
  • Der Entwickler stellte klar, dass dieser Bug kein Problem von Claude Code ist, sondern ein Fehler in der internen Logik von Ghostty

Inhalt des Fixes

  • Die Lösung besteht darin, nicht standardmäßige Seiten nicht wiederzuverwenden, sondern sofort mit munmap freizugeben
    • Wird beim Scrollback eine nicht standardmäßige Seite gefunden, wird stattdessen eine neue Standardseite aus dem Pool erneut allokiert
  • Einige Nutzer schlugen eine Strategie zur Wiederverwendung nicht standardmäßiger Seiten vor, derzeit wurde jedoch bewusst zunächst ein einfacher und sicherer Fix umgesetzt
  • Beispielcode für die Änderung:
    if (first.data.memory.len > std_size) {
        self.destroyNode(first);
        break :prune;
    }
    

Nachverfolgung des Lecks mit VM-Tags

  • Mit der VM-Tag-Funktion des Mach-Kernels unter macOS wurden den Speicherallokationen der PageList spezifische Tags zugewiesen
    • Dadurch lassen sich beim Debugging die Speicherbereiche von Ghostty klar identifizieren
    • Das half erheblich dabei, die Ursache des Lecks zu finden und den Fix zu verifizieren
  • Mit dieser Funktion ließ sich visuell prüfen, ob PageList-bezogener Speicher freigegeben wurde

System zur Vermeidung von Speicherlecks in Ghostty

  • Ghostty erkennt und verhindert Speicherlecks auf verschiedene Weise
    • In Debug-Builds und Unit-Tests wird Zigs Leak-Detecting-Allocator verwendet
    • In der CI werden alle Tests mit valgrind ausgeführt
    • Mit macOS Instruments werden Leaks im Swift-Code geprüft
    • GTK-bezogene PRs werden mit Valgrind-GUI-Tests verifiziert
  • Dieses Leck trat nur unter bestimmten Bedingungen auf und ließ sich daher mit den bisherigen Tests nicht reproduzieren
    • Ein neuer Testfall wurde hinzugefügt, um Regressionen zu verhindern

Fazit

  • Bei diesem Vorfall handelt es sich um das bislang größte bekannte Speicherleck in Ghostty
  • Auch nach dem Fix soll die Situation durch Nutzerberichte und Reproduktionstests weiter überwacht werden
  • Die von der Community bereitgestellten Diagnosedaten und Reproduktionsfälle spielten eine entscheidende Rolle bei der Lösung des Problems
  • Es wird betont, dass eine reproduzierbare Umgebung der Schlüssel zur Behebung von Speicherlecks ist

1 Kommentare

 
GN⁺ 2026-01-11
Hacker-News-Kommentare
  • Wirklich erfreuliche Neuigkeiten. Großer Applaus an alle, die an der Behebung des Problems mitgewirkt haben
    Der Bug wurde bereits letzte Woche in diesem Thread erwähnt
    Claude Code scheint der Auslöser gewesen zu sein, durch den dieser Bug für mehr Nutzer sichtbar wurde, aber es gab auch Leute wie mich, die dasselbe Problem hatten, obwohl sie Claude Code überhaupt nicht benutzt haben
    Die Kriterien dafür, wann eine Seite als „nicht standardmäßig (non-standard)“ eingestuft wird, sind weniger schwarz-weiß als gedacht
    Ich vermute auch, dass das Leak bei Leuten mit Einstellungen wie scrollback-limit = 0 häufiger aufgetreten sein könnte
    Es ist etwas schade, dass die Art der Behebung unnötigerweise nicht standardmäßige Seiten löscht und neu erstellt; vielleicht hätte man alte Seiten, die bereits nicht standardmäßig waren, wiederverwenden können

    • Das wurde im Blogpost bereits behandelt
      Die Funktionsweise von PageList war schon immer dieselbe, und selbst als der Bug vorhanden war, wurde bei der Kapazitätsanpassung nur eine falsche Größe gesehen
      Bei der wahrgenommenen Performance wird es keine Änderung geben
      Die vorgeschlagene Alternative wurde ebenfalls geprüft, aber der aktuelle Ansatz ist durch Benchmark-Daten ausreichend gestützt
      Ich kann meine Meinung dazu noch ändern, aber diesmal habe ich mich darauf konzentriert, das Leak zu beheben, statt das gesamte Modell umzustellen
    • Es war ein Glücksfall, dass das Problem bereits in der Beta-Phase entdeckt und gemeldet werden konnte
      Es war tatsächlich ein reproduzierbarer Bug, der einen segfault ausgelöst hat
    • Übrigens fühlt sich die CLI dank Claude Code wieder attraktiv an
      Mehr als alles andere in den letzten 20 Jahren lässt es die CLI wieder neu wirken
    • Der Thread zum Memory Leak ist hier
  • Ausgezeichneter Artikel. Danke an mitchellh dafür, Ghostty gebaut zu haben
    Ich bin letztes Jahr umgestiegen und habe es nicht bereut
    Etwas überraschend fand ich nur, dass der Fix erst in einem Feature-Release in einigen Monaten enthalten sein soll
    Ich hätte erwartet, dass er in einem Bugfix-Release landet

    • Er ist bereits im neuesten nightly build enthalten
  • Sobald von Seiten die Rede war, dachte ich sofort: „Ah, Memory Pooling“, und dann: „Wahrscheinlich ein Ringpuffer“ — und tatsächlich ging es um Scrollback-Wiederverwendung
    Ich konnte auch die Position des Bugs direkt erraten — es war der Teil, in dem der Seitenspeicher nicht korrekt freigegeben wurde
    Das Diagramm zur Speicherausrichtung war ebenfalls großartig
    Es erinnert einen wieder daran, dass jeder neue Versuch auch die Möglichkeit eines Leaks mit sich bringt

  • Ich bin diese Woche zu Ghostty gewechselt und hatte bei der Entwicklung einer Terminal-UI-App einen OOM-Crash
    Die Struktur nutzte UTF8-Symbole in der Tab-Leiste, und beim Ändern der Terminalgröße kam es sofort zum Crash
    Es war leicht zu reproduzieren, deshalb war ich gerade dabei, einen Bugreport vorzubereiten, als mir auffiel, dass es dem im Blogpost beschriebenen Problem sehr ähnlich sieht
    Ich hoffe, dass es damit behoben ist

  • Ich habe @mitchellh gefragt, mit welchem Tool die Speichervisualisierung erstellt wurde, und da die Website auch mobil gut funktioniert, war ich auch auf den Stack neugierig

    • Verwendet wurde statisches HTML/CSS, generiert mit Opus 4.5
      Der Code für die Visualisierung war einmalig, deshalb wurde eher die Korrektheit als die Qualität geprüft
      Für jeden Blogpost wird ein eigener Namespace getrennt gehalten und nicht wiederverwendet
      Es wurde nur überprüft, dass die Implementierung nichts Merkwürdiges tut (z. B. Bitcoin-Mining, Geheimnisse preisgeben usw.)
      Entscheidend ist die Informationsvermittlung, und solche Diagramme machen den Inhalt deutlich leichter verständlich
  • Ich verfolge die Entwicklung von Ghostty weiterhin
    Es wirkt stellenweise etwas nach Overengineering, aber solche Bug-Postmortems sind für Menschen, die Handwerkskunst lieben, äußerst wertvolles Material

    • Mich würde interessieren, in welcher Hinsicht es für dich nach Overengineering wirkt
  • Ich frage mich, wie ein Rust-basierter Terminal so etwas ohne Performance-Einbußen implementieren würde

  • Selbst ohne viel über Ghostty oder Terminal-Emulatoren zu wissen, war der Artikel leicht verständlich
    Die Zugänglichkeit und die freundliche Erklärung waren beeindruckend

  • Mir wurde wieder bewusst, wie wichtig ein reproduzierbarer Bugreport ist

  • Ich warte darauf, dass jemand sagt: „Mit Rust wäre das nicht passiert“

    • Da wirst du wohl lange warten
      Rust garantiert auf Sprachebene keine „Leak-Sicherheit“ (leak safety)
      Auch sicherer Rust-Code kann Speicher leaken — nur ist das kein Sicherheitsproblem
      Sogar in der Standard-API ist ein Leak ausdrücklich erlaubt, etwa mit Box::leak
      Rust macht es lediglich schwieriger, unbeabsichtigte Leaks zu erzeugen, verhindert sie aber nicht vollständig