共有メモリとは
共有メモリとは複数プロセス間で共有可能なメモリ領域です。共有メモリを利用することでファイル等を介さずに複数プロセスがデータを共有して使用することができます。 UNIX系OS上のORACLEデータベースでMEMORY_TARGETパラメータを無効にしている場合SGAは共有メモリそのものになります。 本ページでは32bit Linux環境で共有メモリを作成するプログラムを作成し、挙動を確認してみます。ソース
Linuxで共有メモリを使用するにはshmgetシステムコールで共有メモリを作成し、共有メモリを使用したいプロセスがshmatシステムコールにより共有メモリにアタッチすることで共有メモリにアクセスできるようになります。 また、shmdtシステムコールで共有メモリをデタッチ(切り離し)し、shmctlシステムコールで共有メモリを削除することができます。以下のプログラムは256MBの共有メモリを作成し、共有メモリに対して全て書き込みを終えるとデタッチ及び共有メモリの削除を行うプログラムで本ページではこのプログラムを使って検証します。
shm_test.c
#include "stdio.h" #include "sys/types.h" #include "sys/ipc.h" #include "sys/shm.h" #include "string.h" #include "stdlib.h" #define PAGESIZE 4096 // Linuxの標準ページサイズ(4K) #define SHMSIZE 268435456 // 共有メモリのサイズ(1024*1024*256=256MB) int shmid; int i; char chr[PAGESIZE] = {0}; char *shmaddr; char *tmp_shmaddr; char tmp = '0'; char *input = &tmp; main(int argc, char* argv[]) { //共有メモリ作成 shmid = shmget(IPC_PRIVATE,SHMSIZE,IPC_CREAT|0666); if (shmid == -1) { printf("shmget error\n"); exit(1); } printf("created shared memory(shmid=%i).\n",shmid); //共有メモリアタッチ shmaddr = shmat(shmid, (void *)0, 0); if (shmaddr == (char *)-1){ printf("shmat error\n"); exit(1); } printf("attached shared memory(shmaddr=%p).\n",shmaddr); tmp_shmaddr = shmaddr; //共有メモリ書きこみ for (i = 0; i <= SHMSIZE - 1;i = i + PAGESIZE){ tmp_shmaddr = tmp_shmaddr + PAGESIZE; strcpy(tmp_shmaddr,chr); //16MB単位で処理を中断 if (i % (PAGESIZE*PAGESIZE) == 0){ printf("press any key..."); gets(input); } printf("address(%p)\n",tmp_shmaddr); } printf("shared memory writed..\n"); printf("press any key..."); gets(input); //共有メモリデタッチ if (shmdt(shmaddr) == -1){ printf("shmdt error\n"); exit(1); } printf("detached shared memory.\n"); //共有メモリ削除 if(shmctl(shmid,IPC_RMID,0) == -1){ printf("shmctl error\n"); exit(1); } printf("deleted shared memory(id=%i).\n",shmid); }
ソースのコンパイル
以下の手順でソースをコンパイルします。(getsシステムコールは危険なため使用しないほうがよいとの警告が出ますが無視します。)[root@linux1 tmp]# cc -c shm_test.c [root@linux1 tmp]# cc shm_test.o -o shm_test shm_test.o: In function `main': shm_test.c:(.text+0x11f): warning: the `gets' function is dangerous and should not be used. [root@linux1 tmp]#
実行及び検証
プログラムを実行すると共有メモリの作成及び共有メモリへのアタッチが実行され、 その後リターンを押す度に16MBの領域を書き込み、256MB書き込み終えた後共有メモリからのデタッチと共有メモリの削除が実施されます。[root@linux1 tmp]#① [root@linux1 tmp]# ./shm_test created shared memory(shmid=1605640). attached shared memory(shmaddr=0xa7f83000). press any key...② ・・・③ address(0xb7f83000) shared memory writed.. press any key...④ detached shared memory. deleted shared memory(id=1605640). [root@linux1 tmp]#⑤共有メモリが存在している間はipcsコマンドで確認するとshmid=1605640でバイトが256MBの共有メモリが作成されていることが確認できます。 また、nattchが1であることから共有メモリへアタッチしているプロセスが1つあることも確認できます。
[root@linux1 ~]# ipcs -m ------ 共有メモリセグメント -------- キー shmid 所有者 権限 バイト nattch 状態 0x00000000 0 root 644 790528 2 対象 0x00000000 32769 root 644 790528 2 対象 0x00000000 65538 root 644 790528 2 対象 0x00000000 98307 root 600 196608 2 対象 0x00000000 131076 root 600 196608 2 対象 0x00000000 163845 root 600 196608 2 対象 0x00000000 196614 root 600 196608 2 対象 0x00000000 1605640 root 666 268435456 1メモリ推移も確認してみると以下のことがわかります。
・共有メモリを作成しただけでは物理メモリにもスワップにも領域は確保されていない(②より)
・書き込まれた領域のみ物理メモリに割り当てられる(③④より)
・物理メモリに割り当てられた共有メモリ領域はcachedに計上される(③④より)(※)
※・・・カーネル2.6以降の機能であるヒュージページを共有メモリに使用した場合は挙動が異なる。
①プログラム起動前 [root@linux1 ~]# ps aux | egrep "(shm_test|VSZ)" | grep -v grep ;free USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND total used free shared buffers cached Mem: 2041652 1729908 311744 0 244064 1277796 -/+ buffers/cache: 208048 1833604 Swap: 2031608 34564 1997044 ②256MBの共有メモリを作成後アタッチした直後 psのVSZ(仮想メモリ)に256MB計上されましたがRSS(物理メモリ使用量)は増えていません [root@linux1 ~]# ps aux | egrep "(shm_test|VSZ)" | grep -v grep ;free USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 14504 0.0 0.0 263652 356 pts/2 S+ 19:31 0:00 ./shm_test total used free shared buffers cached Mem: 2041652 1729908 311744 0 244072 1277792 -/+ buffers/cache: 208044 1833608 Swap: 2031608 34564 1997044 ③16MBの領域に書き込んだ直後 psのRSSとfreeのcachedが16MB増えましたが、buffersとcacheを除いたメモリ使用量はほぼ変わりません [root@linux1 ~]# ps aux | egrep "(shm_test|VSZ)" | grep -v grep ;free USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 14504 0.4 0.8 263652 16744 pts/2 S+ 19:31 0:00 ./shm_test total used free shared buffers cached Mem: 2041652 1746428 295224 0 244076 1294188 -/+ buffers/cache: 208164 1833488 Swap: 2031608 34564 1997044 ④256MBの領域に書き込んだ直後 同じくcachedが256MB増えていますが、buffersとcacheを除いたメモリ使用量はほぼ変わりません [root@linux1 ~]# ps aux | egrep "(shm_test|VSZ)" | grep -v grep ;free USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 14504 2.8 12.8 263652 262496 pts/2 S+ 19:31 0:01 ./shm_test total used free shared buffers cached Mem: 2041652 1989664 51988 0 243976 1537480 -/+ buffers/cache: 208208 1833444 Swap: 2031608 34564 1997044 ⑤プログラム終了後 共有メモリの256MB分が解放されました [root@linux1 ~]# ps aux | egrep "(shm_test|VSZ)" | grep -v grep ;free USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND total used free shared buffers cached Mem: 2041652 1727604 314048 0 243980 1275356 -/+ buffers/cache: 208268 1833384 Swap: 2031608 34564 1997044