C
2016/10/30更新
対応バージョン: gcc-5.4.0
プログラムがメモリを大量に確保するとスワップまで全て使い果たしてシステムが極端に重くなるが、その過程において同じ実行環境にいる全てのプロセスが影響を受けるので、例えばサーバプロセスがクライアントからのリクエストに応答できずにタイムアウトした時の挙動を確かめたいという要件があった時のためにメモリを大量に確保するプログラムを書いた。
処理は単純で、一回あたり100MBのメモリをmalloc()で確保してそれを引数で指定した回数分繰り返すだけである。
尚、引数チェックなどのエラー処理は省略している。
memfull.c
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> int main(int argc, char *argv[]) { int size_mb = 100; /* mallocサイズ(100MB) */ int size = 1024 * 1024 * size_mb; /* mallocサイズ計算(単位:Bytes) */ int times = atoi(argv[1]); /* malloc回数 */ /* 例) 500000回だと100MBx500000=50TB */ char *str; /* malloc()で確保した領域 */ int i; printf("start\n"); for(i = 0; i < times; i++) /* 引数で指定した回数分malloc() */ { str = (char *)malloc(size); if (str == NULL) /* malloc()失敗 */ { printf("malloc() error: %s\n", strerror(errno)); exit(EXIT_FAILURE); } printf("malloc(%07d/%07d)\n", i, times); } printf("end\n"); return(EXIT_SUCCESS); }
このプログラムをコンパイルして実行し、swaponコマンドとvmstatコマンドでメモリの使用量を調べながらプロセスがスワップを使い果たすまでの経過を見る。この間に他のプロセスの挙動を調べる等を行うとよい。
尚、スワップを使い果たすことにより全てのプロセスが想定外の動作をする可能性があるのでテストは他に影響を与えないマシンで行うこと。
% gcc -o memfull memfull.c
まずは5回でテスト。100MB x 5 = 500MB分のメモリを確保するだけなので一瞬で終了し、スワップを使うこともない。
% ./memfull 5 start malloc(0000000/0000005) malloc(0000001/0000005) malloc(0000002/0000005) malloc(0000003/0000005) malloc(0000004/0000005) end
続いてソースの例にあるような500,000回でテストし、100MB x 500,000 = 50TB分のメモリを確保しにいく。ただし実際に確保されるサイズはもっと少ない。
テスト前にそれぞれ別ターミナルでswaponコマンドとvmstatコマンドでメモリの使用量を監視しておく。この例では4GBのうち0.3GB使用している。
swapon -sコマンドを1秒おきに実行
% watch -n 1 swapon -s Every 1.0s: swapon -s Sun Oct 30 10:32:43 2016 Filename Type Size Used Priority /dev/mmcblk0p3 partition 4084732 320264 -1 :
vmstatコマンドを1秒おきに実行
% vmstat 1 procs -----------memory---------- -swap- --io-- -system- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 320264 1063388 14368 168388 0 1 14 21 27 46 1 0 99 0 0 0 0 320264 1063404 14368 168388 0 0 0 0 109 182 0 0 99 0 0 0 0 320264 1063404 14368 168388 0 0 0 0 94 162 0 1 99 0 0 :
監視を仕込んだらテストを行う。
% ./memfull 500000 start malloc(0000001/0500000) malloc(0000002/0500000) malloc(0000003/0500000) : malloc(0421942/0500000) malloc(0421943/0500000) malloc(0421944/0500000) malloc() error: Cannot allocate memory
42万回を越えたところでメモリ確保に失敗してプログラムが終了している。この時swaponとvmstatの状態は以下のようになっている。
swapon
Filename Type Size Used Priority /dev/mmcblk0p3 partition 4084732 4084720 -1 (テスト開始前) Filename Type Size Used Priority /dev/mmcblk0p3 partition 4084732 320264 -1
テスト開始前と比べてスワップを使い果たしているのが分かる。
vmstat
procs ----------memory---------- ---swap--- ----io----- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 3948364 143372 3300 95744 0 85140 0 85136 3792 5269 1 10 73 16 0 2 3 4032828 146600 3444 98064 656 84844 2784 84848 6559 8805 1 13 44 42 0 1 2 4084720 131896 3720 105384 2528 54360 10204 54360 6561 9988 2 16 37 45 0 (テスト開始前) procs ----------memory---------- ---swap--- ----io----- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 320264 1063388 14368 168388 0 1 14 21 27 46 1 0 99 0 0 0 0 320264 1063404 14368 168388 0 0 0 0 109 182 0 0 99 0 0 0 0 320264 1063404 14368 168388 0 0 0 0 94 162 0 1 99 0 0
テスト開始前と比べて以下の違いがあるのが分かる。
memory
メモリ使用量(swpd)と空き容量(free)が逆転
swap
スワップアウト(so)とブロックデバイスへの出力(bo)が頻繁に発生
system
割り込み(in)とコンテキストスイッチ(cs)が増加
cpu
カーネルモードの処理(sy)とI/O待ち(wa)が発生
このようにスワップを使い果たすほどメモリを大量に確保するとシステムの挙動が通常と大きく変わるのでテストをする場合は十分に注意して行うこと。