9 Punkte von GN⁺ 2025-06-14 | 2 Kommentare | Auf WhatsApp teilen
  • Eine Retrospektive, direkt verfasst von Jason Evans, der die Entwicklung von jemalloc maßgeblich vorangetrieben hat. Sie blickt auf rund 20 Jahre jemalloc-Entwicklung in fünf Phasen zurück und dokumentiert offen Erfolge und Misserfolge, die Grenzen von Open Source sowie den Niedergang durch Veränderungen innerhalb eines Unternehmens
  • Der jemalloc-Speicherallokator wurde ab 2004 entwickelt und war fast 20 Jahre lang weit verbreitet, doch aufgrund jüngster interner Veränderungen bei Meta wurde die offizielle Entwicklung eingestellt
  • Über mehrere Phasen hinweg wurden Erfahrungen mit Performance-Optimierung und Portierung gesammelt, etwa bei der frühen Integration in FreeBSD, der Behebung von Firefox-Performanceproblemen und der großflächigen Einführung bei Facebook
  • Im Verlauf verschiedener Herausforderungen wie Speicherfragmentierung und Skalierungsproblemen kamen zahlreiche Funktionen hinzu, darunter Leistungsverbesserungen, Statistikerfassung und Testinfrastruktur
  • Mit dem Wandel der Unternehmenskultur bei Meta wurde die langfristige Entwicklung durch geringere technische Investitionen und das Fehlen zentraler Maintainer gestoppt
  • Die Entfernung von Valgrind und das Ausbleiben von Feedback externer Nutzer wirkten als strukturelle Grenzen innerhalb des Open-Source-Ökosystems
  • Für die Zukunft besteht weiterhin Potenzial für neue Entwicklungen über einen Fork, doch die offizielle Hauptentwicklung wird voraussichtlich nicht mehr fortgesetzt

Überblick über jemalloc

  • jemalloc ist ein 2004 erstmals konzipierter Open-Source-Speicherallokator, der zur Verbesserung von Performance und Skalierbarkeit entwickelt wurde und 20 Jahre lang in wichtigen Open-Source-Projekten und Big-Tech-Infrastrukturen intensiv genutzt wurde
  • Da die Hauptentwicklung zuletzt eingestellt wurde, ist künftig mit Wartung über Forks oder durch einzelne Organisationen zu rechnen

Phase 0: Lyken

  • 2004 begann alles im Zuge der Entwicklung der wissenschaftlichen Programmiersprache Lyken mit einem manuellen Speicherallokator
  • Der Allokator innerhalb von Lyken war im Mai 2005 funktional fertiggestellt
  • Später wurde der Allokator in FreeBSD integriert und aus Lyken entfernt; dort blieb nur ein dünner Wrapper um den Systemallokator zurück
  • Der Grund für die Entfernung war, dass nach der Integration in FreeBSD die fehlenden Eigenschaften des Systemallokators klarer wurden, insbesondere die Nachverfolgung von Zuweisungen pro Thread
  • Interessanterweise wurde die Statistikerfassung, die schon in der Lyken-Zeit benötigt wurde, später zu jemalloc hinzugefügt

Phase 1: FreeBSD

  • 2005, als Multiprozessor-Computer verbreitet wurden, nutzte FreeBSD noch phkmalloc, das für parallele Thread-Umgebungen ungeeignet war
  • Da der Lyken-Allokator klare Vorteile bei der Skalierbarkeit bot, wurde er in FreeBSD integriert und erhielt bald den Namen jemalloc
  • Allerdings traten in KDE-Anwendungen und anderswo schwere Fragmentierungsprobleme auf, sodass das Überleben des Projekts fraglich schien
  • Ursache der Fragmentierung war ein zusammengeführtes Speicherzuweisungsverfahren ohne Größentrennung; nach Untersuchungen wurde die Struktur grundlegend auf einen Algorithmus mit größengetrennter Bereichsaufteilung umgestellt
  • Dieser Prozess wurde in einem BSDCan-Paper von 2006 dokumentiert

Phase 1.5: Firefox

  • 2007 war vor dem Release von Mozilla Firefox 3 die Speicherfragmentierung unter Windows ein großes Thema
  • jemalloc nach Linux zu portieren war einfach, Windows hingegen war schwierig
  • Mozilla forkte jemalloc aus der in FreeBSD libc enthaltenen Version und verbesserte Portabilität und Kompatibilität
  • Mit der Zeit steuerte Mozilla viele Verbesserungen zum jemalloc-Upstream bei, doch die Fork-Version zeigte stets höhere Performance
  • Ob dies an Performance-Regressionen oder an Optimierungen für bestimmte Umgebungen lag, blieb unklar

Phase 2: Facebook

  • Als Evans 2009 zu Facebook kam, war das größte Hindernis für jemalloc das Fehlen geeigneter Werkzeuge wie Profiling und Leak-Erkennung
  • Um dies zu beheben, wurde in jemalloc 1.0.0 pprof-kompatibles Heap-Profiling eingeführt
  • Nach dem Umzug der Entwicklung zu GitHub wurden zusammen mit Nutzern und externen Beitragenden viele Verbesserungen umgesetzt, darunter Testinfrastruktur, Valgrind-Unterstützung, JSON-Statistiken und neues Seitenmanagement
  • Intern half Facebooks gewaltiges Telemetriesystem erheblich bei Performance-Optimierung und der Vermeidung von Regressionen
  • 3.x: Einführung von Testinfrastruktur und Valgrind-Unterstützung
  • 4.x: decay-based purging, JSON-Statistiken hinzugefügt
  • 5.x: Wechsel von chunk- zu extent-basierter Architektur, Grundlage für die Nutzung von 2MiB huge pages geschaffen
  • Die telemetriegestützte Performance-Analyse innerhalb von Facebook spielte eine entscheidende Rolle bei der Optimierung
  • Die Entfernung der Valgrind-Unterstützung in Version 5.0.0 wurde intern beschlossen, weil sie dort nicht genutzt wurde, stieß aber extern, etwa bei Rust-Entwicklern, auf starken Widerstand
  • Spätere organisatorische Veränderungen bei Facebook/Meta verkleinerten das jemalloc-Team, und die Geschäftsstrategie verlagerte sich von Kerntechnologie-Investitionen hin zu Effizienzorientierung
  • Dadurch stagnierte die Entwicklung größerer Funktionen wie Huge Page Allocation, und einige Arbeiten blieben unvollendet
  • Nach Evans’ Ausscheiden 2017 hielt Qi Wang die Entwicklung über mehrere Jahre aufrecht
  • Auch nach dem Führungswechsel hielten mehrere Beitragende das Projekt am Leben, doch es fehlte ein langfristig verantwortlicher Visionsträger

Phase 4: Stasis

  • Der Upstream von jemalloc ist derzeit eingestellt, und auch Meta verfolgt abhängig von internen Anforderungen eine eigene Richtung
  • Die technische Schuld der bestehenden Codebasis ist groß, sodass zunächst umfassendes Refactoring nötig wäre
  • Die Anforderungen von Facebook/Meta und die Bedürfnisse externer Nutzer stimmen nicht mehr überein
  • Sollte die Entwicklung künftig wieder aufgenommen werden, müssten zunächst Hunderte Stunden in den Abbau technischer Schulden investiert werden; der Autor selbst hat dazu keine Motivation mehr
  • Auf Basis des dev-Branches oder von 5.3.0 sind externe Forks möglich, sodass jederzeit neue fork-basierte Projekte entstehen könnten

Rückblick und Lehren

  • Der Konflikt um die Entfernung der Valgrind-Unterstützung entstand aus unzureichender Kenntnis externer Einsatzszenarien
  • Dass jemalloc auch auf Android genutzt wurde, erfuhr man erst zwei Jahre später
  • Das Projekt war auf GitHub zwar vollständig offen, doch in externen Organisationen konnten sich zentrale Beitragende nicht dauerhaft halten
    • Weder Firefox’ Mike Hommey noch der Versuch einer Umstellung auf CMake wurden abgeschlossen
  • Aus dieser Erfahrung folgt, dass bloßes Offenlegen allein kein nachhaltiges unabhängiges Projekt schafft
  • Es wird betont, dass Open Source nicht allein durch Veröffentlichung erhalten bleibt und dass der Aufbau zentraler Beitragender sowie belastbare Governance unverzichtbar sind

Abschließende Worte

  • jemalloc war selbst für den Autor, der seit über 25 Jahren Befürworter von Garbage Collection ist, eine besondere Erfahrung
  • Er konzentriert sich nun wieder auf die Entwicklung von Garbage-Collection-Systemen und spricht allen, die zu jemalloc beigetragen haben, seinen tiefen Dank aus

2 Kommentare

 
ganadist 2025-06-14

Es gibt auch eine Übersetzung des vollständigen Artikels.
https://rosettalens.com/s/ko/jemalloc-postmortem

 
GN⁺ 2025-06-14
Hacker-News-Kommentare
  • Ich kann die Entscheidung nachvollziehen, das Upstream-Repository zu archivieren. Bevor ich Meta verlassen habe, hatte unser Jemalloc-Team schlicht nicht die Kapazität, auf alle möglichen Issues auf GitHub zu reagieren (zum Beispiel hat einmal jemand ein Issue eröffnet, weil die Tests auf Itanium nicht bestanden haben, was ich damals schon etwas komisch fand). Trotzdem finde ich es bedauerlich, das jetzt so zu sehen. Jemalloc ist für mich nach wie vor die performanteste und zugleich am einfachsten nutzbare allgemeine malloc-Implementierung. TCMalloc ist ebenfalls großartig, aber wenn man nicht bazel verwendet, ist es wirklich schwer einzusetzen, finde ich (heutzutage ist es mit cc_static_library in bazel 7.4.0 etwas einfacher geworden, als statische Bibliothek zu exportieren, aber der Punkt bleibt weiterhin relevant). Ich habe vor, Qi zu fragen, ob wir vor der erneuten Archivierung des Repositories noch ein letztes 6.0-Release machen können. Für ein finales Release wäre es meiner Meinung nach gut, einige Standardeinstellungen zu modernisieren. Zum Beispiel wäre es eine große Verbesserung, die irreführend benannte Einstellung „cache oblivious“ standardmäßig zu deaktivieren, damit die 16-KiB-Size-Class nicht unnötig auf 20 KiB anwächst. Ich will damit frühere Entscheidungen (also Jasons ursprüngliche Entscheidung) nicht kritisieren; als ich das damals mit Qi und David besprochen habe, war es ein nachvollziehbarer Grund, dass die TLB-Associativity im Allgemeinen deutlich geringer war als heute. In einem ähnlichen Sinn wäre es auch eine gute Änderung, die Standard-„page size“ von 4 KiB auf etwas Größeres zu erhöhen, etwa 16 KiB. Damit würde der Schwellenwert für große Size-Classes — also der Punkt, an dem man mehrere Allokationen in Slabs unterbringt und ab einer gewissen Größe jede einzeln in einem eigenen Bereich allokiert — von 16 KiB auf 64 KiB steigen, was spürbar etwas bringt. Bevor ich Meta verlassen habe, hatte ich als Letztes noch geprüft, diese Änderung auf einen wichtigen internen Dienst anzuwenden; das war eine Optimierung, die ein paar Prozent CPU-Nutzung eingespart hätte, bei einem leichten Speicheranstieg durch RAM-Fragmentierung. Es gibt noch ein paar weitere Dinge, die ich gern ändern würde (zum Beispiel den Standardwert von metadata_thp von disabled auf auto setzen oder das Extent-Sizing von Slabs weg von exakten Vielfachen der Seitengröße hin zu etwas ändern, das etwa 1 % Verschwendung zulässt, dafür aber Fragmentierung reduziert). Trotzdem wären die zuvor genannten Einstellungen wohl die größten Änderungen

    • Ich bin übrigens genau die Person, die das Issue zum fehlgeschlagenen Itanium-Test-Suite eröffnet hat

    • Genau wegen solcher Erfahrungsberichte aus der Praxis und Insider-Einblicke komme ich immer wieder zu Hacker News zurück. Mich würde interessieren, warum TCMalloc ohne bazel so schwer zu verwenden ist (wirklich als ernst gemeinte Frage)

    • Ich wünschte, solches wichtiges internes Wissen würde in offizieller Dokumentation oder längeren Blogposts veröffentlicht. Im Moment wirkt die offizielle Dokumentation sehr dürftig. Es wäre schön, wenn das Know-how aus all der Arbeit bei Meta geteilt würde, bevor es mit der Zeit verloren geht

    • Es ist etwas schade, dass so großartige Software wegen der Komplexität von Build und Integration nicht so gut genutzt wird, wie sie es verdient hätte

    • Du hast erwähnt, dass „das Jemalloc-Team nicht genug Kapazität hatte, um auf zufällige Issues auf GitHub zu reagieren“. Dazu hätte ich eine Frage: Warum lief das Issue-Management nicht reibungslos, obwohl es bei Meta offenbar ausreichend Leute gab, die das Projekt betreut haben? Falls ich die Situation falsch verstanden habe, korrigiere mich bitte

  • Ich möchte erzählen, wie groß der Einfluss von Jasons Arbeit auf unsere Arbeit ist. Unser Unternehmen ist ziemlich groß und verarbeitet jeden Tag Hunderte Millionen Bilder und Videos. In den ersten Jahren hatten wir enorme Probleme mit Speicherfragmentierung. Dann haben wir eines Tages jemalloc eingeführt, nur zwei Zeilen im Dockerfile geändert, und plötzlich waren alle Probleme gelöst. Heute ist unser Unternehmen mehrere Milliarden Umsatz schwer, und wir verwenden jemalloc in allen Diensten und Dockerfiles. Ich bin wirklich von Herzen dankbar

    • Tatsächlich empfehlen oder verwenden viele bildverarbeitende Services auf Golang-Basis jemalloc. Bei den Top 3 im Thema resize-images (Stand 2025-06-13) nutzt imaginary es hier im Dockerfile, imgproxy wurde unter Bezug auf diese archivierte Dokumentation sogar im imaginary-Repository diskutiert, und auch imagor verwendet jemalloc an dieser Stelle

    • Ganz ehrlich aus Interesse gefragt (überhaupt nicht sarkastisch): Habt ihr auch gespendet? Geld ist doch vielleicht die beste Art, Dankbarkeit zu zeigen

  • Zu der Aussage, jemalloc sei „überraschend schnell“ aus Rust-Binaries entfernt worden: Ich möchte darauf hinweisen, dass dieses Issue tatsächlich nur einer von mehreren Gründen war. Den Hintergrund kann man in diesem Kommentar sehen. Und jemalloc wurde erst ganze zwei Jahre nach dem ersten Aufkommen des Issues vollständig entfernt (siehe dieser PR)

    • Unter den dort erwähnten verschiedenen Issues finde ich interessant, dass das Problem mit hartkodierter Seitengröße auf arm64 im Upstream bis heute nicht gelöst ist. Deshalb müssen App-Entwickler entweder mehrere separate arm64-Linux-Binaries ausliefern oder die Unterstützung für einige Plattformen aufgeben. Ich frage mich, ob es deutlich langsamer geworden wäre, wenn man dynamische Seitengrößen eingeführt hätte (mit dynamischem Anwenden von Binär-Patches im Stil von ftrace aus Performance-Gründen)
  • In allen Game-Engines, die ich über die Jahre gebaut habe, ist es zur Gewohnheit geworden, immer jemalloc zu verwenden. Unter win32 ist es viel schneller als der Standard-Allocator, und es ist auch ein großer Vorteil, auf allen Plattformen denselben Allocator zu verwenden. Kennengelernt habe ich jemalloc, als ich gesehen habe, dass es in FreeBSD integriert ist, und seitdem benutze ich nur noch jemalloc. Ich bin stolz darauf, dass viele Spieler dank jemalloc Freude an meinen Spielen hatten

    • Der Standard-Allocator von Windows ist wirklich schlecht. Jemalloc ist das Beste
  • Das wirkt wie ein guter Artikel — ich frage mich, ob Facebook (heute Meta) jemalloc selbst gar nicht mehr benutzt oder ob es nur noch in einem Wartungsmodus ist. Vielleicht gab es ja einen Wechsel zu tcmalloc oder einem anderen Allocator. Da stand der Satz: „In Facebook Infrastructure Engineering hat sich der Schwerpunkt von Investitionen in Kerntechnologien stärker auf ROI verlagert“

    • Ich bin jetzt seit fast zwei Jahren nicht mehr bei Meta (ich vermute aber nicht, dass sich viel geändert hat), und jemalloc wird dort weiterhin statisch in alle Binaries gelinkt. Auf die Frage, ob man leicht zu tcmalloc oder einem anderen Allocator wechseln könnte: jemalloc ist so tief in das interne Ökosystem des Unternehmens integriert, dass ein Wechsel viel schwieriger ist, als man denkt. Von der Strobelight-Telemetrie-Verkabelung über zahllose Erweiterungen, die speziell auf jemalloc zugeschnitten genutzt werden (zum Beispiel manuelle Arenas mit direkt angepassten Custom-Extent-Hooks), bis hin dazu, dass die meisten Anwendungen sich im Laufe der Zeit so entwickelt haben, dass sie die Eigenschaften von jemalloc bestmöglich ausnutzen — all das hängt zusammen

    • Die große jüngste Veränderung ist, dass die langjährigen Haupt-Maintainer von jemalloc alle weggegangen sind. Trotzdem scheint Facebook intern heute eher mehr Interesse an diesem Projekt zu haben als früher, und nach einigen jüngeren kontroversen Issues bin ich vorsichtig optimistisch, dass es künftig in eine Richtung gehen kann, die sowohl Qi und Jason als auch externe Nutzer berücksichtigt

    • Meta entwickelt seinen eigenen Fork weiterhin aktiv hier

  • Es war mir eine Ehre, über so lange Zeit Teil dieser Arbeit zu sein, die von Firefox bis Facebook Einfluss hatte

    • Auch ich möchte an dieser Stelle meinen Dank aussprechen. Ich hatte nicht erwartet, dass dieser Beitrag heute erscheinen würde, aber es war mir eine Ehre, auch nur ein kleiner Teil dieser großen Reise zu sein. Ich möchte mich auch bei @je, qi, david sowie bei den damaligen und späteren Mitwirkenden bedanken

    • Ich denke, deine Führung hat so weit wie möglich Früchte getragen, indem du dafür gesorgt hast, dass Facebook weiter in Kerntechnologien investiert. Innovationen wie GraphQL, PyTorch und React waren nur möglich, weil es dieses Fundament gab

  • Das FTA-Zitat — „Unter unmöglichen Optionen tun Menschen nur noch eines von drei Dingen: 1) unter extremem Druck schlechte Entscheidungen treffen, 2) sich unter extremem Druck fügen oder 3) Umgehungswege suchen“ — klingt kaum wie eine Arbeitsatmosphäre, die man sich vorstellen möchte

    • Meine bittere Erfahrung ist, dass fast jeder Arbeitsplatz, den ich seit 2008 hatte, genau so war
  • Ich glaube, jemalloc ist der einzige Allocator, der unter macOS malloc/free ähnlich reibungslos wie mit LD_PRELOAD überschreiben kann (zumindest war das um 2020 so). Über den zonenbasierten Ansatz kann es sich leicht als Standard-Allocator einschleusen und erfüllt auch die speziellen Anforderungen von Apple an Allocatoren gut. Andere Third-Party-Allocatoren sind an diesen Anforderungen oft gescheitert

    • Allerdings funktioniert diese Methode nur unter der Annahme, dass der System-Allocator von macOS seine internen Strukturen nicht verändert; soweit ich mich erinnere, gab es tatsächlich etwa zwei Fälle, in denen Apple etwas geändert und das Ganze dadurch kaputtgemacht hat

    • Soweit ich weiß, kann mimalloc auf dieselbe Weise arbeiten, sicher bin ich mir aber nicht

  • Soweit ich weiß, ist jemalloc gegenüber malloc aus glibc in jeder Hinsicht besser, und Benchmarks zeigen anscheinend immer bessere Leistung. Warum ist es dann nicht der Standard-Allocator? Das frage ich mich als Außenstehender schon länger

    • Unter FreeBSD ist jemalloc bereits Standard. Wenn man den malloc austauschen will, wäre es einfacher, gleich auch libc durch FreeBSD libc zu ersetzen, und dann wäre es nur folgerichtig, auch den Kernel auf FreeBSD umzustellen. Als unser Unternehmen mit Facebook fusionierte, habe ich einem Kollegen begeistert jemalloc vorgestellt — aber wir waren schon auf FreeBSD, daher war es für alle ohnehin selbstverständlich

    • Ich bin kein Allocator-Engineer und das ist keine Expertenmeinung, aber ich habe einmal mit einem Engineer gesprochen, der einen OS-Allocator betreut hat. Laut ihm verschaffen Custom-Allocator einem einzelnen Prozess oft enorme Vorteile bei der Speicherallokation, verschlechtern dafür aber tendenziell die Fairness der Allokation auf Systemebene. Aus Sicht eines System-Allocators ist eine globale Optimierung schwieriger, wenn einzelne Prozesse sehr unterschiedliche Muster haben. Deshalb wird jemalloc gerade in Service-Umgebungen oft empfohlen, in denen implizit gilt: „Wichtig ist vor allem mein eigener Prozess“

    • Ich glaube nicht, dass es einen technischen Grund gibt, warum jemalloc nicht der Standard-Allocator sein könnte. Auf FreeBSD ist es das ja tatsächlich (wie auch im Artikel erwähnt). Meinem Verständnis nach ist das Problem eher politischer als technischer Natur

    • Jemalloc ist in großen produktiven Umgebungen erprobt, die Lizenz ist sehr freizügig und die Performance ist belegt. Ich frage mich ernsthaft, wer außer „ideologischer Reinheit“ und Legacy-Trägheit eigentlich davon profitiert, an glibc malloc festzuhalten. Warum man sich immer noch hinter „Kompatibilität“ versteckt, ist mir schleierhaft

    • Früher war ein großes Problem bei alternativen Allocatoren, dass freigegebener Speicher nie an das OS zurückgegeben wurde, sondern als Dirty Pages gehalten wurde (das wurde letztlich verbessert, zeigt aber gut die unterschiedlichen Prioritäten von Allocatoren). Und in Wirklichkeit laufen die meisten Prozesse nur mit einem Main-Thread oder haben sonst fast nur idle Threads. Für solche Umgebungen sind auf Multithreading optimierte Allocatoren womöglich überdimensioniert und eher Ballast. Außerdem möchte ich erwähnen, dass viele offenbar nicht bedenken, dass es praktisch keinen wirklichen Unterschied macht, ob der Kernel die Kosten für das Zeroing von Pages trägt oder ein User-Prozess sie intern zur Wiederverwendung selbst nullt

  • Ich fände es besser, wenn man lieber den Link zum Blogpost zum GitHub-Repository hinzufügen würde. Für zukünftige Besucher des Repos wäre es wichtig, diesen Kontext zu kennen und nachlesen zu können