メモリについて 2011.06.05 by yan
Linuxのメモリ管理
Linuxではプログラムからアクセス可能なメモリを割り当てる方法として
- malloc(ライブラリ)
- mmap(システムコール)
の方法があります。
mallocはプログラムのある領域にあらかじめメモリを用意(この領域をヒープと呼ぶ)しておき そこから必要な量だけを使用します。プログラムの操作で行います。
mmapはカーネルが管理しているメモリーから必要な量をプログラムに 割り当てます。カーネルの機能を使用します。
mallocはメモリの獲得、返却を繰り返すとフラグメントが発生して 獲得、返却のスピード及びメモリの使用効率が落ちるなどの問題が知られています。
ヒープ領域はプログラム開始時は領域だけが予約されていてメモリその物は 割り当てらていません。割り当てらていないメモリに対して読み書きを行うと ページフォールトという割り込みが発生します。
カーネルがページフォールトを検出するとアクセスのあったメモリに実際のメモリを 割り当てます。
mmapはメモリの管理自体はOSが行っているのでフラグメント等の問題は起こりません。 しかし、割り当ての単位はページサイズ(intel系では4096バイト)で行われるので これ以下のメモリをmmapで獲得すると効率が悪くなります。
Linuxのmallocでは
- 128KB未満のメモリー要求に対してはヒープから割り当てる。
- 128KB以上のメモリー要求に対してはmmapを使用する。
ことによって上記の問題に対処しています。
MPDパッチによるメモリロックの問題点
mpdでメモリのロックを導入したのは
音楽再生中のメモリー割り当てでカーネルに介入されたくない
為です。
mpdではmallocを用いてメモリの獲得を行いますが、ヒープでも説明したように mallocで獲得したメモリもページフォールトによってカーネルが介入します。
音楽再生中にページフォールトが発生しないようにするためには音楽再生前に ヒープ領域に実メモリを割り当ておく必要があります。
その方法として
- a. mallocで大量のメモリを獲得して初期化する。その後、その領域を開放する。
- これにより、以後のmallocはすでに割り当てられているメモリを使用する 事ができ、ページフォールトの発生を防ぐことができる。
その予約の為の指定が realtime_optionのheap_reserveです。
- b. メモリをロックする。
- Linuxにはmlockというシステムコールがあってそれを使用すると 仮想空間(通常のプログラムが動作するメモリの領域)に実メモリを 割り当てる事ができます。
その指定が realtime_option のmemlock
a,bのいずれかを使用する事で音楽再生中のカーネルの介入が防げると思っていました。
しかし、malloc(Linuxのメモリ管理)で説明したようにLinuxのmallocでは128KB以上のメモリはmmapを 使用します。a.の方法ではヒープにメモリを割り当てることができません。
google-perftoolsのtcmallocによる改善
それを回避する為に google-perftoolsに入っているtcmallocを使用しました。
参考: TCMalloc : Thread-Caching Malloc (http://goog-perftools.sourceforge.net/doc/tcmalloc.html)
通常のmallocとtcmallocそれぞれの場合でメモリの使用状況は以下のようになります。
(いずれの場合もmemlockは“no”です)
通常のmalloc heap_reserve 0 heap_reserve 10240KB ------------------------------------------------------- VmPeak: 49308 kB 59552 kB VmSize: 49308 kB 49308 kB VmLck: 0 kB 0 kB VmHWM: 13928 kB 24156 kB VmRSS: 13928 kB 13928 kB VmData: 27568 kB 27568 kB VmStk: 1044 kB 1044 kB VmExe: 272 kB 272 kB VmLib: 20068 kB 20068 kB VmPTE: 52 kB 48 kB ------------------------------------------------------- tcmalloc heap_reserve 0 heap_reserve 10240KB ------------------------------------------------------- VmPeak: 50428 kB 60668 kB VmSize: 50428 kB 60668 kB VmLck: 0 kB 0 kB VmHWM: 14432 kB 24672 kB VmRSS: 14432 kB 24672 kB VmData: 28560 kB 38800 kB VmStk: 1044 kB 1044 kB VmExe: 272 kB 272 kB VmLib: 20192 kB 20192 kB VmPTE: 48 kB 60 kB -------------------------------------------------------
VmDataが初期化済みデータ領域で通常のmallocでは heap_reserveの値によらず 一定ですが,tcmallcではheap_reseveで指定した分大きくなっています。
その他、VmSize,VmRssも通常のmallocではheap_reserveによる変化は ありません。また、ヒープは一度拡張されるとそれが小さくなる事はありません。
これにより、tcmallocでは自プロセス空間からheap_reserveで指定した 量のメモリを割り当てている事が分かります。
通常のmallocを使った場合、heap_reserveによるヒープの初期化は無駄な 操作になります。
realtime_optionでメモリを割り当てる方法
realtime_optionでメモリを割り当てる方法をまとめると
通常のmallocを使う場合 memlock "yes" heap_reserve 0 tcmallocを使う場合 (1) memlock "yes" heap_reserve 0 または (2) memlock "no" heap_reserve "10240" (値は調整する必要あり)
になります。
memlockの場合、ヒープ領域全体をロックします。ヒープの使われていない領域 は無駄になります。それを回避したい場合は (2)でヒープの初期化を行います。
また、memlock “yes”とした場合、mpdはswapされなくなります。
しかし、voyageの場合は通常swapを設けませんからmemlock “no”でも問題はないと 思います。
tcmallocの使い方
google-perftoolsのインストール
tcmallocは google-perftools に入っています。
voyage mpd には以下のようにしてインストールします。
libgoogle-perftools0_1.7-1_i386.deb をダウンロード
dpkg -i libgoogle-perftools0_1.7-1_i386.deb
mpdでtcmallocを使う
コンパイル時に指定する方法と起動時に指定する方法の二つがあります。
- コンパイル時にmpdのconfigureで
LIBS=-ltcmalloc_minimal を追加する。
- 起動時にtcmalloc_minimalを指定する。
-ltcmalloc_minimalを指定しないでmakeしたmpdに対しては実行時に tcmallocの使用を指示する事ができます。 /etc/init.d/mpd に export LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.0 を追加する。 例: ... ... PATH=/sbin:/bin:/usr/sbin:/usr/bin NAME=mpd DESC="Music Player Daemon" DAEMON=/usr/bin/mpd MPDCONF=/etc/mpd.conf START_MPD=true export LD_PRELOAD=/usr/lib/libtcmalloc_minimal.so.0 <-- 追加 # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 ... ...