- jemalloc の開発を主導した Jason Evans 自身が書いた回顧録で、約20年にわたる jemalloc 開発の歩みを5段階に分けて振り返り、成功と失敗、オープンソースプロジェクトの限界、そして企業内の変化による衰退の過程を率直に記した文章
- jemalloc メモリアロケータは2004年から始まり、約20年間広く使われてきたが、最近の Meta の社内変化により公式な開発が中断された
- 初期の FreeBSD 統合、Firefox の性能問題の解決、Facebook による大規模採用など、複数の段階で 性能最適化とポーティングの経験 を蓄積した
- ストレージ断片化問題 やスケーラビリティの問題など、さまざまな課題を経るなかで、性能向上に加えて 統計収集、テストインフラ など多様な機能が追加された
- Meta への企業文化の変化とともに、技術投資の減少、コアメンテナーの不在 により長期的な開発が中断された
- Valgrind の削除や外部ユーザーからのフィードバック不足 など、オープンソース生態系との断絶が構造的な限界として作用した
- 今後 フォーク(fork) による新たな発展の可能性は残されているが、公式なメイン開発は今後行われない見込み
jemalloc 概要
- jemalloc は2004年に初めて考案された オープンソースのメモリアロケータ で、性能とスケーラビリティの改善を目的に開発され、20年間にわたり主要なオープンソースプロジェクトやビッグテックのインフラで活発に活用されてきた
- 最近メイン開発が中断され、今後は フォーク や各組織単位での保守が見込まれる
Phase 0: Lyken
- 2004年、科学技術計算向けプログラミング言語 Lyken の開発過程で、手動メモリアロケータから出発した
- Lyken 内部のアロケータは2005年5月に機能面で完成した
- その後アロケータは FreeBSD に統合され、Lyken ではシステムアロケータの薄いラッパーだけを残して削除された
- 削除の理由は、FreeBSD 統合後にシステムアロケータの不足部分(スレッドごとの割り当て量追跡)だけが明確になったためだった
- 興味深いことに、その後の jemalloc には Lyken 時代に必要としていた 統計収集機能 が追加された
Phase 1: FreeBSD
- 2005年、マルチプロセッサコンピュータ が一般化しつつあった時期、FreeBSD は phkmalloc を使用していたが、並列スレッド環境には適していなかった
- Lyken のアロケータにはスケーラビリティ改善に明確な利点があり、これを FreeBSD に統合する中で、やがて jemalloc という名前が付けられた
- しかし KDE アプリケーションなどで 深刻な断片化問題 が発生し、存続可能性すら疑われた
- 断片化の原因は サイズ区分のない統合空間割り当て方式 にあり、研究の末に サイズ別領域分離アルゴリズム へと構造を大幅に変更した
- この過程の内容は2006年の BSDCan 論文に記録されている
Phase 1.5: Firefox
- 2007年、Mozilla Firefox 3 のリリースを控え、Windows 環境でのメモリ断片化が大きな課題となっていた
- jemalloc を Linux に移植するのは容易だったが、Windows は厄介だった
- FreeBSD libc に格納されていた jemalloc を Mozilla がフォークし、移植性と互換性の改善を進めた
- 時間が経つにつれ Mozilla は jemalloc アップストリームに多くの改善を貢献したが、常に フォーク版のほうが高い性能 を示した
- これが性能回帰の問題によるものか、特定環境向けの最適化によるものかは不明である
Phase 2: Facebook
- 2009年に Facebook に入社した時点で、jemalloc の 最大の障害要因 はツール不足(プロファイリング、リーク検出)だった
- これを補うため、pprof 互換ヒーププロファイリング 機能を jemalloc 1.0.0 で導入した
- 開発は GitHub に移管された後、ユーザーや外部コントリビューターとともに テストインフラ、Valgrind サポート、JSON 統計、新しいページ管理 など多くの改善が行われた
- 社内では Facebook の 巨大なテレメトリシステム のおかげで、性能最適化と回帰防止に大きな助けとなった
- 3.x: テストインフラと Valgrind サポートを導入
- 4.x: decay ベースのメモリ解放(decay-based purging)、JSON 統計を追加
- 5.x: chunk から extent ベースの設計へ変更し、2MiB huge page 活用の基盤を整備
- Facebook 内部の telemetry ベースの性能分析 が最適化に決定的な役割を果たした
- 5.0.0 バージョンでの Valgrind サポート削除は社内で使われていないことを理由に決定されたが、Rust 開発者など外部 からの反発は強かった
- その後 Facebook/Meta の組織変化により jemalloc チームは縮小され、コア技術投資より効率性重視 の事業戦略へと転換した
- これにより Huge Page Allocation のような大型機能の開発は停滞し、一部の作業は完了しなかった
- 2017年に Evans が退職した後も、Qi Wang 主導で数年間にわたり開発は維持された
- チームリーダーシップ移譲後も複数のコントリビューターがプロジェクトを維持してきたが、長期的ビジョンを担う管理者は不在となった
Phase 4: Stasis(停滞状態)
- 現在、jemalloc の アップストリーム開発は終了 した状態で、Meta も社内ニーズに応じて別の方向性を追求するようになった
- 既存コードベースの技術的負債が大きく、大規模なリファクタリングが先行して必要である
- Facebook/Meta の要求と外部ユーザーの要求はもはや 一致していない
- 今後開発を再開するなら、数百時間以上の技術的負債の整理が先に必要 であり、本人にその意欲はない
dev ブランチまたは 5.3.0 を基準にした 外部フォーク は可能であり、いつでも フォークベースの新しいプロジェクト が現れる可能性はある
回顧と教訓
- Valgrind サポート削除 で生じた対立は、外部の利用実態の把握不足 に起因していた
- Android で jemalloc が使われていた事実も、2年が過ぎてからようやく知った
- プロジェクトは GitHub で 完全に公開 されていたが、外部組織における 中核コントリビューターが継続しなかった
- Firefox の Mike Hommey や CMake への移行の試みも、いずれも 未完 に終わった
- 経験上、単に公開するだけで 持続可能な独立プロジェクト になるわけではない
- オープンソースは公開するだけでは維持されず、コアコントリビューターの育成とガバナンスの確保 が不可欠であることを強調している
締めくくりの言葉
- jemalloc は、25年以上にわたり ガベージコレクション支持者 だった著者にとっても特別な経験だった
- 現在は再びガベージコレクションシステムの開発に集中しているが、jemalloc に協力してくれたすべての人々への深い感謝を述べている
2件のコメント
全文の翻訳版もあります。
https://rosettalens.com/s/ko/jemalloc-postmortem
Hacker News の意見
upstream リポジトリをアーカイブするという決定には理解を示す立場です。Meta を離れる前の時点では、私たちの Jemalloc チームには GitHub に上がってくるありとあらゆる issue に対応する余力がありませんでした(たとえば、誰かが Itanium 環境でテストが通らないという issue を上げたことがありましたが、私には少し笑ってしまう出来事でした)。それでも、この状況を見ると残念に感じます。今でも jemalloc は、私の考える汎用 malloc 実装の中で、最も高性能で、しかも使いやすい選択肢だと感じています。TCMalloc も素晴らしいですが、bazel を使わないなら本当に使いづらいケースだと思います(最近では bazel 7.4.0 に
cc_static_libraryが追加され、静的ライブラリとしてエクスポートするのが少し楽になりましたが、それでもその点は依然として大きいです)。私は Qi に、リポジトリを再びアーカイブする前に最後の 6.0 リリースを一度出せないか聞いてみようと考えています。最後のリリースなら、デフォルト設定を少し現代的にしてもよい気がします。たとえば、名前に反して誤解を招くcache oblivious設定をデフォルトで無効にして、16 KiB の size-class が無駄に 20 KiB へ膨らむ問題を防ぐのは大きな改善です。以前の選択(つまり Jason の初期の決定)を非難したいわけではなく、当時 Qi や David と議論した際には、一般に TLB associativity が今よりずっと低かったという納得できる理由がありました。同じ文脈で、デフォルトのpage sizeを 4 KiB からもっと大きい値(16 KiB くらい)に上げるのもよい変更になるでしょう。そうすると、大きな size-class の基準(複数の割り当てを slab に入れ、一定サイズを超えるとそれぞれ個別の range に割り当てる切り替え点)が 16 KiB から 64 KiB に上がるので効果が大きいです。Meta を離れる前に最後に主要な内部サービスへこの変更を適用しようと検討したことがありましたが、CPU 使用量が数 % 下がる代わりに、RAM 断片化によるわずかなメモリ増加がある最適化でした。ほかにも変えたい点はいくつかあります(たとえばmetadata_thpのデフォルトをdisabledからautoに変える、slab の extent sizing をページサイズの厳密な倍数から、約 1% の無駄を許容する代わりに断片化を減らす方向へ変える、など)。それでも、先に挙げた設定が最も大きな変更になるでしょうItanium テストスイート失敗の issue を登録した本人は私です
こういう実体験や内部者のインサイトがあるからこそ Hacker News に通い続けているのだと思います。TCMalloc を bazel なしで使いにくい理由が何なのか気になります(本当に純粋な興味で聞いています)
こうした重要な内部知識が、公式ドキュメントやブログ記事のような、よりまとまった形の資料として公開されてほしいです。現状では公式ドキュメントがあまりにも薄いと感じます。Meta 内で積み重ねられた数多くの知見が、時間の経過で忘れられてしまう前に共有されてほしいと思います
素晴らしいソフトウェアなのに、ビルドと統合の過程が複雑なせいで十分に活用されていない現実が少し残念です
「Jemalloc チームには GitHub に上がってくるランダムな issue に対応する余力が十分になかった」とありましたが、気になる点があります。Meta にそのプロジェクトを管理する十分な人数がいたにもかかわらず、issue 対応が円滑でなかった背景は何だったのでしょうか。私が状況を誤解しているなら訂正してください
Jason の仕事が私たちの業務にどれほど大きな影響を与えているかを伝えたいです。私たちの会社は、毎日何億件もの画像や動画を処理する、かなり大きな規模の会社です。立ち上げ初期の数年間、メモリ断片化の問題で本当に苦しみました。ところがある日 jemalloc を導入し、Dockerfile でたった 2 行変えただけで、すべての問題が解決するという経験をしました。今では数百億の売上を持つ会社となり、すべてのサービスと Dockerfile で jemalloc を使っています。心から感謝しています
実際、多くの golang ベースの画像処理サービスが jemalloc を推奨または使用しています。resize-images トピックの上位 3 件のサービスを見ると(2025-06-13 時点)、imaginary は この Dockerfile で使っていますし、imgproxy についても アーカイブされた文書を参考に imaginary の repo 内で議論されています。imagor も この箇所で jemalloc を使っています
本当に純粋な興味で聞きます(皮肉はまったくありません)。寄付もしたのでしょうか。お金で感謝を示すのが最大の謝意ではないでしょうか
「jemalloc が Rust バイナリから予想より早く外された」という意見について、実際にはその issue は複数ある要因の一つにすぎなかったことを共有したいです。このコメントに背景があります。そして jemalloc が完全に削除されたのは、その issue が最初に提起されてから実に 2 年後でした(参考: この PR)
ここ数年、自分が作るすべてのゲームエンジンで jemalloc を必ず使うのが習慣になっています。win32 環境ではデフォルト allocator よりはるかに速く、すべてのプラットフォームで同じ allocator を使える利点も大きいです。FreeBSD で jemalloc が統合されたのをきっかけに知り、それ以来ずっと jemalloc だけを使っています。jemalloc のおかげで、多くのゲームユーザーが楽しめていることに誇りを感じています
良い記事だという印象です — Facebook(今は Meta)が jemalloc 自体をもう使っていないのか、それとも保守だけしている段階なのか気になります。もしかすると tcmalloc や別の allocator に移行した可能性もあるのでしょうか。「Facebook インフラエンジニアリングでは、コア技術への投資より ROI 重視へ軸足が移った」という一文がありました
私が Meta を退職したのはほぼ 2 年前ですが(今も大きくは変わっていないと思います)、jemalloc は今なお Meta 内のすべてのバイナリに静的リンクされて使われています。tcmalloc や別の allocator に簡単に移行できるかという問いに対しては、jemalloc は社内エコシステムに非常に深く組み込まれているので、思った以上に難しいというのが答えです。Strobelight のテレメトリ plumbing から、jemalloc 向けに使われる多数の extensions(たとえば独自の custom extent hook を使う manual arena など)、そして実際に大半のアプリケーションが jemalloc の特性を最大限引き出すよう設計されるまでに進化してきた経緯まで、すべてが絡み合っています
最近の大きな変化があるとすれば、jemalloc の長期メンテナたちが全員去ったことです。ただその一方で、以前よりも Facebook 内でこのプロジェクトへの関心が高まり始めており、最近いくつかの論争的な issue を経たことで、今後は Qi と Jason、そして外部ユーザーの立場も考慮する方向へ進めるのではないかという前向きな見方もあります
Meta は今も独自 fork を ここで活発に開発しています
Firefox から Facebook に至るまで、長い期間にわたって大きな影響を持つこの仕事に関われたことを光栄に思います
私も今が感謝を伝えるのにふさわしいタイミングだと思います。この記事が今日出るとは予想していませんでしたが、大きな旅路のほんの一部でも共にできて光栄でした。@je、qi、david、そして当時とその後の貢献者たちにも感謝したいです
Facebook 内でコア技術への継続投資を可能にしたあなたのリーダーシップは、最大限の実を結んだと思います。GraphQL、PyTorch、React のような革新が実現できた背景には、こうした基盤があったからです
「不可能な選択肢しかないとき、人は 1) 極度の圧力の中で悪い決定をするか、2) 極度の圧力の中で従うか、3) 迂回するしかない」という FTA の引用は、職場の雰囲気としては想像しがたいものです
jemalloc は macOS 上で malloc/free を LD_PRELOAD のように滑らかにオーバーライドできる唯一の allocator だと思います(2020 年ごろの時点では)。zone ベースの方式で簡単にデフォルト allocator として割り込めますし、Apple 特有の allocator 要件にもよく適合しています。ほかの third-party allocator はこの要件のせいでしばしば失敗していました
ただし、この方式は macOS のシステム allocator が内部構造を変えないことを前提にしているため、実際には Apple の変更で壊れた例が 2 回ほどあったと記憶しています
mimalloc も同じ方式で動くと理解していますが、確信はありません
jemalloc は glibc の malloc と比べてあらゆる面で改善されており、ベンチマーク結果を見る限り常に高性能に思えるのですが、それならなぜデフォルト allocator ではないのか、外部の立場から気になっていました
FreeBSD ではすでに jemalloc がデフォルトです。malloc を変えたいなら libc も FreeBSD libc に置き換えるほうが簡単でしょうし、そうするなら kernel も FreeBSD にするのが自然です。Facebook と合併した当時、こちらの同僚に jemalloc を紹介して盛り上がったのですが、すでに FreeBSD だったので当たり前のように使われていました
私は allocator エンジニアではないので専門的な意見ではありませんが、以前 OS allocator を管理しているエンジニアと話したことがあります。その人の話では、custom allocator はある 1 プロセスにとってはメモリ割り当てで圧倒的に有利になる一方、システム全体の割り当て公平性は悪化しがちだということでした。システム allocator の立場からすると、個々のプロセスがそれぞれ異なるパターンを持つと全体最適化が難しくなります。だから多くのサービス環境では、「今このプロセスさえ良ければいい」という前提のもとで jemalloc がよく勧められるのだと思います
jemalloc がデフォルト allocator になれない技術的理由はないと思います。実際、FreeBSD ではデフォルトです(記事でも触れられています)。私の理解では、この問題は技術というより政治に近いです
jemalloc は実際に大規模な本番環境で検証され、ライセンスも非常に緩く、性能も実証済みです。それなのに glibc malloc に固執する理由はいったい何なのか、「イデオロギー的純粋性」やレガシー慣性以外に、誰がこの状態で得をしているのか本気で気になります。なぜ今なお「互換性のため」と言い訳し続けるのかと問いたい気分です
昔は代替 allocator が free されたメモリを決して OS に返さず、dirty page として抱え込み続けるのが大きな問題でした(これは最終的には改善されましたが、allocator の優先順位の違いを示す代表例です)。そして実際には、大半のプロセスはメインスレッド 1 本だけで動くか、ほとんどアイドルなスレッドしかありません。マルチスレッド最適化 allocator は、そうした環境では過剰で、むしろ負担になる場合があります。ちなみに、カーネルがページを zero 化するコストと、ユーザープロセスが内部再利用のために zero 化するコストに実質的な差がないことを、多くの人が見落としている点にも触れておきたいです
むしろ ブログ記事へのリンク を GitHub リポジトリに追加してほしいです。今後リポジトリを訪れる人が、この文脈を知って参考にできることは重要だと思います