malloc()のヒープの拡大を確認する
malloc()の実装は(細かい部分は無視して)
・OSからヒープをまとめて取得する。
・malloc()されるとヒープを分けあたえる。
・ヒープに余裕がない場合は、ヒープを拡大する。
と言う感じだと思います。
でこの流れを実感できる方法があったのでメモ。
/proc/[pid]/mapsはpid番号のプロセスに割り当てられたメモリ領域です。
試しにここをのぞいてみます。
ソースはこんな感じ。
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main(void){ char cmd[256]; snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid()); system(cmd); return 0; }
環境はこんな感じ。
$ cat /proc/version Linux version 2.6.20-16-generic (root@terranova) (gcc version 4.1.2 (Ubuntu 4.1.2-0ubuntu4)) #2 SMP Thu Jun 7 20:19:32 UTC 2007
実行するとこんな感じ。
*見て分かると思いますが、08048000-08049000はアドレスの範囲です。
$ ./a.out 08048000-08049000 r-xp 00000000 08:02 481863 /home/****/src/c/proc_map/a.out 08049000-0804a000 rw-p 00000000 08:02 481863 /home/****/src/c/proc_map/a.out b7dc0000-b7dc1000 rw-p b7dc0000 00:00 0 b7dc1000-b7efc000 r-xp 00000000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7efc000-b7efd000 r--p 0013b000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7efd000-b7eff000 rw-p 0013c000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7eff000-b7f02000 rw-p b7eff000 00:00 0 b7f0f000-b7f11000 rw-p b7f0f000 00:00 0 b7f11000-b7f2a000 r-xp 00000000 08:02 6224 /lib/ld-2.5.so b7f2a000-b7f2c000 rw-p 00019000 08:02 6224 /lib/ld-2.5.so bfa36000-bfa4b000 rw-p bfa36000 00:00 0 [stack] ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
次にmalloc()を行ってみる。
*テストなので、エラー処理やfree()はしていません。
1$ cat main.c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main(void){ char cmd[256]; char *p; p = malloc(0x100); snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid()); system(cmd); return 0; }
これを実行してみる
$ ./a.out 08048000-08049000 r-xp 00000000 08:02 481863 /home/****/src/c/proc_map/a.out 08049000-0804a000 rw-p 00000000 08:02 481863 /home/****/src/c/proc_map/a.out 0804a000-0806b000 rw-p 0804a000 00:00 0 [heap] b7da2000-b7da3000 rw-p b7da2000 00:00 0 b7da3000-b7ede000 r-xp 00000000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7ede000-b7edf000 r--p 0013b000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7edf000-b7ee1000 rw-p 0013c000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7ee1000-b7ee4000 rw-p b7ee1000 00:00 0 b7ef1000-b7ef3000 rw-p b7ef1000 00:00 0 b7ef3000-b7f0c000 r-xp 00000000 08:02 6224 /lib/ld-2.5.so b7f0c000-b7f0e000 rw-p 00019000 08:02 6224 /lib/ld-2.5.so bfbb1000-bfbc6000 rw-p bfbb1000 00:00 0 [stack] ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
注目するところはここ。
[heap]というのが増えているのが分かる。
0804a000-0806b000 rw-p 0804a000 00:00 0 [heap]
ここが、「・OSからヒープをまとめて取得する。」という部分。
さらにmalloc()をしてみる。
1$ cat main.c #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main(void){ char cmd[256]; char *p; int i; for(i=0;i<1000;i++){ p = malloc(0x100); } snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid()); system(cmd); return 0; }
実行してみると分かるが[heap]の領域が増えているのが分かる。
$ ./a.out 08048000-08049000 r-xp 00000000 08:02 481867 /home/yasusi/src/c/proc_map/a.out 08049000-0804a000 rw-p 00000000 08:02 481867 /home/yasusi/src/c/proc_map/a.out 0804a000-0808c000 rw-p 0804a000 00:00 0 [heap] b7e26000-b7e27000 rw-p b7e26000 00:00 0 b7e27000-b7f62000 r-xp 00000000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7f62000-b7f63000 r--p 0013b000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7f63000-b7f65000 rw-p 0013c000 08:02 25028 /lib/tls/i686/cmov/libc-2.5.so b7f65000-b7f68000 rw-p b7f65000 00:00 0 b7f75000-b7f77000 rw-p b7f75000 00:00 0 b7f77000-b7f90000 r-xp 00000000 08:02 6224 /lib/ld-2.5.so b7f90000-b7f92000 rw-p 00019000 08:02 6224 /lib/ld-2.5.so bff58000-bff6d000 rw-p bff58000 00:00 0 [stack] ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]
ちなみに、r-xpは書き込み禁止、rw-pは書き込めることを示しています。
つまり、
char *p = "hoge"; int i;
上記の"p"はr-xp、"i"はrw-pになります。
r-xpに書き込みを行うとSegmentation faultになりますが、
割り当てられていなくても、rw-pに書き込みは可能です。
もちろんmapsにないエリアに書き込みを行ってもSegmentation faultになります。
ポインタ関係のバグで、Segmentation faultになったり、何事もなく処理が進んだりするのはこのあたりが関係しています。