!!!参考 https://techracho.bpsinc.jp/hachi8833/2017_12_28/50109 https://qiita.com/kamina_zzz/items/0540f663832e07ee1b10 http://www.rarul.com/mt/log/2018_09.html https://qiita.com/kaityo256/items/bf6563361c502bbf062e !!!概要 RubyのSidekiqなどのマルチスレッド処理でメモリの使用量が増え続けてしまうことがある。 メモリリークしているわけではなく、Rubyのメモリ管理とmallocの仕様によりメモリの断片化が発生している。 メモリリークのようにメモリを消費し続けるわけではなく、対数的にある上限に収束するように増加する。 {{img memory.png}} mallocはマルチスレッドでの排他処理の効率を上げるためにスレッド単位メモリアリーナを実装している。 以下引用 1. あるスレッドでmallocを呼び出します。このスレッドは、前回アクセスしたメモリアリーナ(他のアリーナが作成されていない場合はメインのアリーナ)のロック取得を試みます。 2. そのアリーナを利用できない場合は、次のメモリアリーナのロック取得を試みます(メモリアリーナが他にもある場合) 3. 利用できるアリーナがない場合は、アリーナを1つ作成してそれを使う。この新しいアリーナは、連結リストの最後のアリーナにリンクされる。 マルチスレッドかつI/O処理を実行するCRubyにスレッド単位メモリアリーナが使われ、新しいメモリアリーナが大量に作成されてしまう。 マルチスレッドでもI/Oを行っていない場合はGVM(Global VM Lock)によって制御されるためメモリアリーナの奪い合いは発生しない。 !!!解決策 !!方法1:メモリアリーナを削減する MALLOC_ARENA_MAX環境変数でメモリアリーナの最大数を設定できる。 メモリアリーナ数を調整することでメモリの使用量を減らすことが出来るが、排他処理が多くなるためパフォーマンスの低下に繋がる。 メモリの使用量とパフォーマンスのバランスを確認しながら設定する必要がある。 !!方法2:jemallocを使う アロケータをmallocからjemallocに変更する。 jemallocもスレッド単位アリーナを実装していますが、mallocで起きる断片化を回避する設計になっている。 {{category2 プログラミング言語,Ruby}}