メモリアロケーション
今回はプロセスへのメモリ割り当てについて記載する。
プロセス生成時及び生成後の追加割り当ては以下のようになっている。
プロセス生成時
プロセス生成時はまず、実行ファイルを読み出して得られる情報を元にメモリの割り当てを行う。
具体的には、コード領域のサイズ + データ領域のサイズから、プログラムの実行に必要なメモリサイズを計算し、この領域を物理メモリに割り当て、必要なデータをコピーすることになる。
なお、実際の物理メモリの割り当て処理については、デマンドページングアルゴリズムのためもう少々複雑になるが、そちらについては別のエントリに記載する。
続いてプロセスのためのページテーブルを作成し、仮想アドレス空間と物理アドレス空間のマッピングを行う。
最後に所定のアドレスから実行開始をすることで処理は完了する。
追加割り当て時
プロセスが新規にメモリを要求した際は、カーネルは新規にメモリを割り当て、対応するページテーブルを作成した上で、割り当てたメモリに対応する仮想アドレスをプロセスに返却する。
実際のメモリ割り当てを見る
以下のような処理を実装し、結果から、実際にメモリが割り当てられた際の様子を見てみる。
- プロセスのメモリマップ情報 (/proc/[pid]/maps) を表示
- メモリを新たに 100 MB 確保
- サイドメモリマップを表示
コードは以下。
mmap.c
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#define BUFFER_SIZE 1000
#define ALLOC_SIZE (100*1024*1024)
static char command[BUFFER_SIZE];
int main(void) {
pid_t pid;
pid = getpid();
snprintf(command, BUFFER_SIZE, "cat /proc/%d/maps", pid);
puts("====== memory map before new memory allocation ======");
fflush(stdout);
system(command);
void *new_memory;
new_memory = mmap(NULL, ALLOC_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (new_memory == (void *) -1)
err(EXIT_FAILURE, "mmap() failed.");
puts("");
printf("====== succeeded in allocating new memory: address = %p; size = 0x%x ======", new_memory, ALLOC_SIZE);
puts("");
puts("====== memory map after new memory allocation ======");
fflush(stdout);
system(command);
if (munmap(new_memory, ALLOC_SIZE) == -1)
err(EXIT_FAILURE, "munmap() failed.");
exit(EXIT_SUCCESS);
}
コンパイルして実行すると以下の出力が得られる。
$ ./mmap
====== memory map before new memory allocation ======
00400000-00401000 r-xp 00000000 ca:01 524414 /home/ec2-user/LinuxBootCamp/Chapter5/mmap
00601000-00602000 rw-p 00001000 ca:01 524414 /home/ec2-user/LinuxBootCamp/Chapter5/mmap
7f8501bb8000-7f8501d72000 r-xp 00000000 ca:01 2608 /lib64/libc-2.17.so
7f8501d72000-7f8501f71000 ---p 001ba000 ca:01 2608 /lib64/libc-2.17.so
7f8501f71000-7f8501f75000 r--p 001b9000 ca:01 2608 /lib64/libc-2.17.so
7f8501f75000-7f8501f77000 rw-p 001bd000 ca:01 2608 /lib64/libc-2.17.so
7f8501f77000-7f8501f7c000 rw-p 00000000 00:00 0
7f8501f7c000-7f8501f9d000 r-xp 00000000 ca:01 2601 /lib64/ld-2.17.so
7f8502193000-7f8502196000 rw-p 00000000 00:00 0
7f850219b000-7f850219d000 rw-p 00000000 00:00 0
7f850219d000-7f850219e000 r--p 00021000 ca:01 2601 /lib64/ld-2.17.so
7f850219e000-7f850219f000 rw-p 00022000 ca:01 2601 /lib64/ld-2.17.so
7f850219f000-7f85021a0000 rw-p 00000000 00:00 0
7ffd6d1d6000-7ffd6d1f7000 rw-p 00000000 00:00 0 [stack]
7ffd6d1fb000-7ffd6d1fe000 r--p 00000000 00:00 0 [vvar]
7ffd6d1fe000-7ffd6d200000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
====== succeeded in allocating new memory: address = 0x7f84fb7b8000; size = 0x6400000 ======
====== memory map after new memory allocation ======
00400000-00401000 r-xp 00000000 ca:01 524414 /home/ec2-user/LinuxBootCamp/Chapter5/mmap
00601000-00602000 rw-p 00001000 ca:01 524414 /home/ec2-user/LinuxBootCamp/Chapter5/mmap
7f84fb7b8000-7f8501bb8000 rw-p 00000000 00:00 0
7f8501bb8000-7f8501d72000 r-xp 00000000 ca:01 2608 /lib64/libc-2.17.so
7f8501d72000-7f8501f71000 ---p 001ba000 ca:01 2608 /lib64/libc-2.17.so
7f8501f71000-7f8501f75000 r--p 001b9000 ca:01 2608 /lib64/libc-2.17.so
7f8501f75000-7f8501f77000 rw-p 001bd000 ca:01 2608 /lib64/libc-2.17.so
7f8501f77000-7f8501f7c000 rw-p 00000000 00:00 0
7f8501f7c000-7f8501f9d000 r-xp 00000000 ca:01 2601 /lib64/ld-2.17.so
7f8502193000-7f8502196000 rw-p 00000000 00:00 0
7f850219b000-7f850219d000 rw-p 00000000 00:00 0
7f850219d000-7f850219e000 r--p 00021000 ca:01 2601 /lib64/ld-2.17.so
7f850219e000-7f850219f000 rw-p 00022000 ca:01 2601 /lib64/ld-2.17.so
7f850219f000-7f85021a0000 rw-p 00000000 00:00 0
7ffd6d1d6000-7ffd6d1f7000 rw-p 00000000 00:00 0 [stack]
7ffd6d1fb000-7ffd6d1fe000 r--p 00000000 00:00 0 [vvar]
7ffd6d1fe000-7ffd6d200000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
新たなメモリ獲得後は ”7f84fb7b8000-7f8501bb8000 rw-p 00000000 00:00 0” という行が追加されており、新規にメモリ領域が確保されたことが確認できる。
また実際にこれが 100MB であることが以下のように確認できる。
$ python -c "print(0x7f8501bb8000 - 0x7f84fb7b8000)"
104857600