jubatus/jubatus — Issue #18: Memory fragmentation in recommender?
Author: kuenishi
Created: 2012-02-17 07:48:00+00:00
State: open

サーバーを単体で起動し、連続して5万〜10万回ほどupdate_row（とseimilar_row_from_id）を繰り返すとメモリ量が爆発的に増えるが、クライアントを止めてしばらく待つとメモリが解放されもとにもどる。topでみると本当に必要な量の100倍程度はカーネルから取得ししまっている模様。

update_rowの中のrecommenderのudpate_rowをコメントアウトすると起きなくなる。
update_rowと同時に大きなメモリを確保すると(100回に一回256MBとか)消費ペースが下がる
サーバーでのstringなどの値渡しを参照渡しにすると消費ペースが下がる
OSSとしてリリースするまでには必ず修正が必要。ただし報告書の処理が優先

inverted_indexが一番増加ペースが早いが、lsh, minhashでも少なからず起きている
-> chtである程度分散しておけば問題ないかも？！
id数が多いと起きやすい（100万〜1万程度で起きる、100だと起きない

#3 tokoroten が2ヶ月前に更新

メモリの断片化がおきていることはほぼ間違いない。

attic/test3/recomender.cppの実験プログラムを利用して、
recomenderに「セッションを繋いで、無限にupdate_rowを走らせる」プログラムAと、
recomenderに「セッションを繋いで、10回だけupdate_rowをした後に、セッションを切断」を無限に繰返すプログラムBを作成。

プログラムAのみ実行した場合、メモリ利用量は増大
プログラムBのみ実行した場合、メモリ量は変化せず
プログラムAとBを同時に実行した場合、メモリ量は変化せず
プログラムAの実行中にプログラムBを実行した場合、メモリ量が減少していく

そのため、メモリの断片化が発生しているようである。
セッションが切れたタイミングをトリガーにして、なんらかのシステムコールが走って、
断片化されたメモリのコンパクションが実行されている模様。

そのため以下のもので解決可能であると考える。
・メモリの断片化を引き起こさないmallocの実装を採用
・メモリの断片化を引き起こさないstringの実装を採用
・タイマー割り込みで定期的にメモリコンパクションを実行するシステムコールを発生させる

＃C++でgcみたいな挙動をすることって始めてみたよ

#4 tokoroten が2ヶ月前に更新

http://linuxjm.sourceforge.jp/html/LDP_man-pages/man2/move_pages.2.html
このあたりを使うと断片化したメモリを集約できるのかな？

#5 kuenishi が約1ヶ月前に更新
担当者 を tokoroten にセット
優先度 を 高め から 通常 に変更

僕と契約してカーネルハッカーになってよ！！

#6 tokoroten が約1ヶ月前に更新

カーネル周りのメモリコンパクションのトリガーを引いてみましたが、効果がありませんでした。
やはりプロセスがメモリを握ったまま離さないようです。

以下は私の推測です。
・スレッドがメモリを要求するときに新しいメモリ領域を要求する。
・スレッドがメモリを開放するときにプロセスが領域をプールする。
・新しいコネクションがあった時に、プロセスがカーネルにメモリ領域を返却する。

どうやらこのような流れになっていそうです。
ですので、プロセスがカーネルにメモリを返却するタイミング、スレッドがカーネルが保持しているメモリ領域を利用するようにする、
こういった形で解決できないかと考えています。