glibc メモリ動作のチューニング
この記事の英語版に更新があります。ご覧の翻訳には含まれていない変更点があるかもしれません。
最終更新日 2023年05月15日(月)
Table of Contents
アプリケーションの保守担当者は、MALLOC_ARENA_MAX
環境変数を調整することによってアプリケーションパフォーマンスとメモリ使用をチューニングできます。
最新バージョンの glibc では、malloc が割り当てることのできるメモリのために複数のメモリプールが使用されます。特に、マルチスレッドプログラムの場合は、複数のメモリプールを使用してメモリ割り当てを高速化 (ロックを削減) し、全体的なパフォーマンスを向上させることができます。glibc malloc 領域の実装についての詳細は、この記事を参照してください。
一部のメモリ割り当てパターンでは、このパフォーマンス向上により、アプリのある程度大きなメモリ消費が犠牲になる場合があります。これは特に、多数のスレッドを作成および破棄し、それらのスレッドで大量のメモリを割り当てるプログラムに当てはまる可能性があります。
2019 年 9 月 24 日の時点では、Heroku に新しいアプリケーションをデプロイすると、デフォルトで MALLOC_ARENA_MAX=2
になります。アプリでこの値が設定されているかどうかは、次を実行して確認できます。
$ heroku run bash
~$ env | grep MALLOC_ARENA_MAX
MALLOC_ARENA_MAX=2
アプリでこの値がデフォルトで設定されていない場合は、次のように手動で設定できます。
$ heroku config:set MALLOC_ARENA_MAX=2
MALLOC_ARENA_MAX
をチューニングするタイミング
アプリケーションで MALLOC_ARENA_MAX=2
が設定されているが、大量のメモリが残っている場合は、この値を大きくすることによって応答時間を少し短縮できる可能性があります。このテストはかなり前に実行されましたが、それ以降、その比較的小さなマイナス面と比較して、この設定のプラスの効果を示す多数のレポートがありました。
- 「Malloc Can Double Multi-threaded Ruby Program Memory Usage」(malloc はマルチスレッド Ruby プログラムのメモリ使用量を 2 倍にすることができる)
- 「Taming Rails memory Bloat」(Rails のメモリの肥大化を抑制する)
アプリケーションで MALLOC_ARENA_MAX=2
を使用していない場合は、R14 エラーが発生していないかどうか、またはアプリケーション関連のメトリクスでメモリ消費の増加が報告されていないかどうかを調べてください。この値を 2
に設定すると、アプリケーションのメモリ消費を削減するのに役立ちます。
MALLOC_ARENA_MAX
として選択する値
64 ビットシステム上の glibc でのメモリプールのデフォルトの数は CPU コアの数の 8 倍です (Heroku 上の dyno で確認される CPU コアの数は dyno タイプによって異なる)。
アプリが glibc のデフォルト設定で適切に実行されない場合は、アプリの MALLOC_ARENA_MAX
環境設定を変更することによってその動作を調整できます。
$ heroku config:set MALLOC_ARENA_MAX=2
この設定をアプリ全体に適用するのではなく、不適切なメモリ動作を示す特定のプロセスタイプにのみ適用したい場合は、環境設定の前に Procfile コマンドを付加することができます (sidekiq: env MALLOC_ARENA_MAX=2 bundle exec sidekiq
)。
値 MALLOC_ARENA_MAX
の選択は一般に、パフォーマンスとメモリ消費とのトレードオフです。MALLOC_ARENA_MAX
を設定しない場合は最高のパフォーマンスが得られますが、メモリ使用が増える可能性があります。MALLOC_ARENA_MAX
を “2” または “1” に設定すると、glibc は少ないメモリプールと潜在的に少ないメモリを使用しますが、これによりパフォーマンスが低下する可能性があります。当社で行ったテストに基づいて、アプリのメモリ使用を削減しようとする場合は “2” の値をお勧めします。
アプリケーションが依然としてメモリに制約されている場合は、メモリ使用量を削減する方法に関するアイデアが含まれている「R14 - Memory Quota Exceeded in Ruby (MRI)」(R14 - Ruby (MRI) でのメモリ割り当ての超過) の記事を参照してください。