2021-12-01 Ruby x jemalloc
Ruby x jemalloc
Railsアプリのメモリ断片化を抑制する
Ruby(Railsアプリケーション)のメモリ肥大化はメモリの断片化が原因。
これに対しては下記の2つのソリューションが推奨されている。
- Either use a completely different memory allocator than the one in glibc – usually jemalloc
- 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% ほど高速っぽい。
改善事例
- Reducing Sidekiq Memory Usage with Jemalloc | Brandon Hilkert
- How jemalloc improved memory usage of our Rails application
- How we decreased our memory usage with jemalloc - DEV Community
- Fullstaq Ruby: First impressions, and how to migrate your Docker/Kubernetes Ruby apps today - DEV Community
参考リンク
- jemalloc
- Scalable memory allocation using jemalloc - Engineering at Meta
- jemalloc について調べたのでまとめた - zonomasaの日記
追記: 一方 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 を使うと良いらしい。