差分
記憶管理
,/* 動的なメモリ領域確保 */
== 実メモリ ==
タが展開されていて、それに対し正しいアクセス制御できなければシステムは
正常に動かなくなってしまいます。
実メモリはいうまでもなく限定された貴重な資源です。実メモリはプログラムが使うだけでなく、I/Oのキャッシュに使ってI/Oパフォーマンスを改善することにも使います。
もしプログラムの中で既にアクセスされないメモリ空間を実メモリにかかえていていて、実メモリをキャッシュに使えないような場合は、せっかくの実メモリが有効に使えていない状態になってしまいます。
そこでプログラムが抱えたまま使っていないメモリ空間を外部記憶装置に送り出し、その分の実メモリをI/Oのキャッシュに利用するならば、全体のパフォーマンスが向上するはずです。このようにプログラムに使うメモリ空間を管理するだけでなくシステム全体を通して実メモリを有効に使うことが重要になります。
</ref>
ですが、多くのCPUの最小ページサイズが4KBなのでLinuxのページサイズはデフォルトで4KBとなっています。
==== MMU ====
[[File:Memory_fig2.png|thumb|left|300px|仮想記憶のモデル]]
プロセスに割り当てられているメモリリソースとしてのメモリのアドレスは仮想的なアドレス空間に割り当てられます。仮想アドレス空間での仮想アドレスは、実際の実メモリの物理的な意味でのアドレスとは一致しません。
仮想アドレス空間と実メモリアドレス空間のマッピングは、それを管理する MMU (Memory Management Unit) というハードウェアによってマップされています。
実メモリに入りきらないものを外部記憶装置に書き出し、必要になったら実メモリに読み込もうというのが仮想記憶です。
実メモリアドレス空間より仮想アドレス空間よりが大きい状態になっていれば、実メモリ上にない仮想アドレスを要求することが発生します。
例えば32ビットアーキテクチャーの場合(2<sup>32</sup> / 4GB ) は仮想記憶空間として1048576(2<sup>20</sup>)のページを持つことになります。もし512MBの物理メモリしか搭載していないマシンは内部で131072ページしか持っていません。のページを持つことになります。<ref>IA-32アーキテクチャで物理アドレス拡張(PAE)を使うことはひとまずおいておきます。</ref>もし512MBの物理メモリしか搭載していないマシンは内部で131072ページしか持っていません。
スワップの状態は/proc/swapsを見るとわかります。下の例はサイズが1453872K (1.45GB)バイトである/dev/hda3パーティションがスワップに使われているという意味です。
<pre class="bash">
% cat /proc/swaps
Filename Type Size Used Priority
/dev/hda3 partition 1453872 0 -1
</pre>
たとえばswapf01という名前のスワップファイルを作ってシステムにスワップファイルとして登録する時は次のようにします。
<pre>
# /bin/dd if=/dev/zero of=swapf01 bs=8192 count=256
# /sbin/mkswap swapf01 2048
# sync
# swapon swapf0
</pre>
;補足: Linux 2.6.32でスワップについて試したことのメモランダム [[linuxのswapについて私が知っている二、三の事柄]]
==== zswap ====
zswap[https://www.kernel.org/doc/Documentation/vm/zswap.txt]は、 Linux kernel version 3.15 から入った仮想メモリ圧縮 (Virtual Memory Compression)を利用したスワップで、外部記憶装置にページをスワップするのではなく、実メモリ上に作った圧縮ブロックデバイスにページをスワップする機能でです。実メモリ上にスワップできなくなった時に、これまでのスワップ機能で用意しているスワップ領域にスワップを始めます。
ディスクなどメモリから比較すると低速なストレージへのI/Oが少なくなるため、頻繁にページアウトが発生しスワップファイルへのI/Oがボトルネックになるようなケースでは有用な機能です。フラッシュメモリを使ったSSDのような書き換え上限があるような外部記憶装置上にスワップファイルを作ると頻繁なスワップはメディアの劣化が進むためzswapが有効であるという議論もあります。圧縮処理が行われるため、その分、CPUに負荷がかかります。ただし、それがI/Oのオーバーヘッドによる処理の低下と比較し、相対的にどちらに利益があるかは、個々のシステム構成によって変化する議論であることは注意してください。
== 局所参照性 ==
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
char *p;
size_t areasize=1024*1024*512;
if ((p=(char *)malloc(areasize)) == NULL) {
perror("malloc");
}
sleep(10);
free(p);
}
</syntaxhighlight> * 実行例 <pre class="bash">$ cc malloctest.c ./a.out &[1] 93627$ ps -o user,pid,vsize,rss,cmd USER PID VSZ RSS CMDhironobu 87439 10752 6392 bashhironobu 93627 526788 580 ./a.outhironobu 93628 9928 3440 ps -o user,pid,vsize,rss,cmd </pre> このプログラムは512MBメモリ領域をmalloc(3)を使いアロケーションしています。実行時の状況をpsで見てみると、VSZが525528、RSSが284となっています。VSZはVirtual を使いアロケーションしています。実行時の状況をpsで見てみると、VSZが526788、RSSが580となっています。VSZはVirtual memory Sizeのことで仮想記憶もふくめて全部のメモリサイズです。RSSはReal Set Sizeのことで、実メモリ(物理的なメモリ)で専有しているメモリサイズです。つまり、このプログラムは約523.5MBもの記憶領域を取っているにもかかわらず、実際の実メモリ上では284KBしか取られていません。 で専有しているメモリサイズです。つまり、このプログラムは約527MBもの記憶領域を取っているにもかかわらず、実際の実メモリ上では580KBしか取られていません。
次の ps コマンドを実行してみましょう。するとRSSでソートされて、USER / COMMAND / RSS / VSZの順で表示されます。
<pre class="bash">
$ ps -Ao user,args,rss,vsize --sort rss
USER COMMAND RSS VSZ root [keventd] 0 0 root [ksoftirqd_CPU0] 0 0
...
hironobu emacs20 -geometr 9076 11112/usr/bin/emacs23 15732 42140 canna hironobu gedit 23204 173232 hironobu /usropt/sbingoogle/chrome/chrome - 107380 359600</cannas 17540 19152pre>
;調べてみよう: vmstatで観察してみましょう。vmstatは仮想記憶のステータス観察するためのツールです。1秒毎に表示するオプションで動作させながら、先程のプログラムを改造し徐々に記憶を取るようなプログラムにして動かし、観察してみましょう。
<pre class="bash">
% vmstat 1 <- 1秒毎に表示
procs memory swap io system cpu
2 1 0 29964 1140 368 2128 316 124 79 310 485 817 37 9 54
...
</pre>
== コピーオンライトとその実際 ==
Linuxのカーネルではプロセスが親から引き継がれたメモリ領域や実行コードなどを引き継いでいても、そこに書き換えが発生するまで、実際のメモリ領域はとりません。書き込みがあって始めてメモリ領域を確保し、中身をコピーして別なものにします。このことをコピーオンライト(CoW: Copy on Write)といいます。このような仕組みにより、高速に新しいプロセスを生成したり、あるいはメモリの効率的な利用が出きるようにしています。
/proc/(プロセスid)/smapsは、カーネル内の該当プロセスのメモリ利用状況を表示するAPIです。それを使って実験したいと思います。
dashはDebian版軽量シェルでシステムのシェルスクリプトを実行するのに使われます。
さて、$$はシェル自身のプロセスidですので、/proc/$$/smapsとすると現在使っているシェルのメモリ利用状況がわかります。
注目するのは Shared_Clean と Private_Clean の値です。
Shared_Clean はシェアしているメモリです。
Private_Clean は自らのメモリです。
クリーンな、という意味は、まだそのページは変更されていない(書き込みがおこっていない)という意味です。
まず最初、dashを起動してdashシェル環境でメモリ利用状況をみます。
この時、引き継ぐものがないのでPrivate_Cleanが76kB (= Rssの値と同じ)、Shared_Cleanが0kBとなっています。
次にdashの中でさらにdashを起動します。つまり最初のdashが親プロセスとなった新しいdashです。
この上で両方の値をみるとPrivate_Cleanが0kB、Shared_Cleanが76kB(= Rssの値と同じ)となっています。
つまり、子プロセス側となったdashのメモリは、この時点ではシェアしているものを使っていることがわかります。
<pre class="bash">
$ dash
$ cat /proc/$$/smaps | head -9
08048000-08060000 r-xp 00000000 08:01 4825 /bin/dash
Size: 96 kB
Rss: 76 kB
Pss: 76 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 76 kB
Private_Dirty: 0 kB
Referenced: 76 kB
$ dash
$ cat /proc/$$/smaps | head -9
08048000-08060000 r-xp 00000000 08:01 4825 /bin/dash
Size: 96 kB
Rss: 76 kB
Pss: 34 kB
Shared_Clean: 76 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 0 kB
Referenced: 76 kB
</pre>
== mmap ==
$ cc mmap.c
$ ./a.out
[a][b][c][d][e][f][g]$
</pre>
ファイルもメモリも、さらにデバイスすらも単純な1つの記憶空間として扱おうというコンセプトが単一レベル記憶です。
現在、オペレーティングシステムレベルでサポートしているのはIBM社のSystem iシリーズ<ref>
IBMのサイトにあるIBM System iの単一レベル記憶の解説 : http://www-06.ibm.com/systems/jp/i/seminar/reconf/reconf1.shtml
</ref>
ぐらいしかないので、
インターネット上で説明を探すとIBM System iの機能=単一レベル記憶の定義みたいな説明しかありませんが、
== 脚注 ==