Ruby x jemalloc

Railsアプリのメモリ断片化を抑制する

Ruby(Railsアプリケーション)のメモリ肥大化はメモリの断片化が原因。

これに対しては下記の2つのソリューションが推奨されている。

  1. Either use a completely different memory allocator than the one in glibc – usually jemalloc
  2. Set the magical environment variable MALLOC_ARENA_MAX=2.

What causes Ruby memory bloat? – Joyful Bikeshedding

メモリアロケーターをjemallocに切り替える

jemalloc が使える環境ならメモリアロケーターを jemalloc に切り替えるのが良さそう。

Rubyをjemalloc付きでコンパイルする必要はありません(一応可能ですが)。LD_PRELOADを使えば動的に読み込めます。

Ruby: mallocでマルチスレッドプログラムのメモリが倍増する理由(翻訳)|TechRacho by BPS株式会社 (原文: Malloc Can Double Multi-threaded Ruby Program Memory Usage)

LD_PRELOAD に shared object のパスを渡して ruby を実行すればOKそう。

LD_PRELOAD=/path/to/libjemalloc.so.2

参考. Getting Started · jemalloc/jemalloc Wiki

確認方法

下記のようにとあるRails/Rubyプロセスにおいて jemalloc を使われているかは下記の通り確認できる。

$ strings /proc/{process_no}/maps  | grep jemalloc
7f59e5ff8000-7f59e6028000 r-xp 00000000 103:03 12712        /usr/lib64/libjemalloc.so.1
7f59e6028000-7f59e6227000 ---p 00030000 103:03 12712        /usr/lib64/libjemalloc.so.1
7f59e6227000-7f59e6229000 rw-p 0002f000 103:03 12712        /usr/lib64/libjemalloc.so.1

Rubyアプリケーションのメモリ使用量上昇問題をjemallocを使うことで解決しました - Studyplus Engineering Blog

下記のMALLOC_CONF=stats_print:true を設定する方法でもいける。

jemalloc が設定されていない場合、Begin jemalloc statistics 以下が表示されない。

$ MALLOC_CONF=stats_print:true ruby -e "exit"
___ Begin jemalloc statistics ___
Version: "5.3.0-0-g54eaed1d8b56b1aa528be3bdd1877e59c56fa90c"
Build-time option settings
...省略...

ref. Ruby: Herokuでjemallocが有効かどうかを確認する方法|TechRacho by BPS株式会社

パフォーマンス測定

Fullstaq Ruby では内部的に jemalloc をアロケーターにしたRubyを使っているようだ。

Fullstaq Ruby は jemalloc のPro/Con についてこう述べている。

  • Pro: Uses less memory than the original Ruby.
  • Pro: Is usually faster than the original Ruby. (How much faster? AppFolio benchmark, Ruby Inside benchmark)
  • Con: May not be compatible with all gems (though such problems should be rare).

下記のベンチマークが参考になった。

Benchmarking Ruby’s Heap: malloc, tcmalloc, jemalloc — AppFolio Engineering

jemalloc が 10% ほど高速っぽい。

改善事例

参考リンク

追記: 一方 Rust では jemalloc が外された

Announcing Rust 1.32.0 | Rust Blog

while jemalloc usually has great performance, that’s not always the case. Additionally, it adds about 300kb to every Rust binary. We’ve also had a host of other issues with jemalloc in the past.

パフォーマンス的には一定寄与するが、300kbのバイナリ増加 + jemalloc 起因の問題が看過できないぞ、ということらしい。

引き続き jemalloc を使いたい場合は jemallocator という crate を使うと良いらしい。

jemallocator - crates.io: Rust Package Registry