【要約】メモリリークの正体は glibc malloc だった ── Python 以外でも効く LD_PRELOAD 1 行のアロケータ差し替え [Zenn_Python] | Summary by TechDistill
> Source: Zenn_Python
Execute Primary Source
// Problem
PKSHA Technologyのエンジニアが、ECS Fargate上のFastAPIサーバにおいて、負荷試験中にメモリ使用率が単調増加し、OOMが発生する問題に直面した。\n・リクエスト数に応じてメモリ使用率が増え続ける。\n・負荷が落ち着いてもメモリが解放されず高止まりする。\n・NumPy等のネイティブライブラリが大小様々なメモリ確保・解放を繰り返す。\n・マルチスレッド環境でglibc mallocの断片化が発生しやすい。
// Approach
アプリケーションコードを一切変更せず、動的リンカの機能を利用してメモリアロケータをjemallocへ差し替える手法を採用した。\n・Dockerfileで
libjemalloc2 をインストールする。\n・環境変数 LD_PRELOAD に libjemalloc.so.2 のパスを指定する。\n・これにより、プロセスが呼ぶ malloc/free をjemallocの実装に置き換える。\n・保険としてGunicornの --max-requests によるワーカーの自動入れ替えも併用する。// Result
jemallocの導入により、メモリ管理の挙動が劇的に改善された。\n・メモリ使用率が50%台で横ばいとなり、単調増加が解消された。\n・高負荷試験においてもOOMが発生しなくなった。\n・Pythonに限らず、RubyやNode.jsなど、glibc mallocを使用する他の言語環境でも適用可能な汎用的な対策であることが示された。
Senior Engineer Insight
> 「メモリリーク=コードのバグ」という固定観念を捨てるべき知見だ。特にNumPy等のネイティブ拡張を多用するAI/ML系ワークロードでは、低レイヤーの挙動が支配的となる。ただし、LD_PRELOADは「魔法」であり、原因の切り分けを困難にするリスクもある。導入時は必ず計測に基づき、Gunicornの
--max-requests 等の運用回避策と組み合わせる多層防御が肝要だ。