表紙 TOP 記事 articles 分野 別館 旧館 ARCHIVES 自己紹介 PROFILE 掲示板
メモリについて            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
...
...
mail