[解決済み] なぜ、このメモリイーターは本当にメモリを食べないのか?
質問
Unixサーバでメモリ不足(OOM)状態をシミュレートするプログラムを作りたいのですが、どうすればいいですか?私はこの超簡単なメモリイーターを作りました。
#include <stdio.h>
#include <stdlib.h>
unsigned long long memory_to_eat = 1024 * 50000;
size_t eaten_memory = 0;
void *memory = NULL;
int eat_kilobyte()
{
memory = realloc(memory, (eaten_memory * 1024) + 1024);
if (memory == NULL)
{
// realloc failed here - we probably can't allocate more memory for whatever reason
return 1;
}
else
{
eaten_memory++;
return 0;
}
}
int main(int argc, char **argv)
{
printf("I will try to eat %i kb of ram\n", memory_to_eat);
int megabyte = 0;
while (memory_to_eat > 0)
{
memory_to_eat--;
if (eat_kilobyte())
{
printf("Failed to allocate more memory! Stucked at %i kb :(\n", eaten_memory);
return 200;
}
if (megabyte++ >= 1024)
{
printf("Eaten 1 MB of ram\n");
megabyte = 0;
}
}
printf("Successfully eaten requested memory!\n");
free(memory);
return 0;
}
で定義されただけのメモリを消費します。
memory_to_eat
であり、現在ではちょうど50GBのRAMとなっています。1MBずつメモリを割り当て、さらに割り当てに失敗した箇所を正確に表示するので、どの最大値を食べたのかがわかります。
問題は、それがうまくいくかどうかです。物理メモリが1GBのシステムでもです。
topを確認すると、このプロセスは50GBの仮想メモリを食べ、常駐メモリは1MB以下しか食べていないことがわかります。本当に消費するメモリイーターを作る方法はないでしょうか?
システムの仕様 Linuxカーネル3.16( Debian ) おそらくオーバーコミット有効で (確認方法は不明)、スワップ無し、仮想化されています。
解決方法は?
を使用する場合
malloc()
実装はシステムカーネルにメモリを要求します。
sbrk()
または
mmap()
システムコール)、カーネルは、あなたがメモリを要求したことと、アドレス空間内のどこに配置されるかを記録するだけです。
そのページを実際にマッピングすることはまだありません。
.
その後、プロセスが新しい領域内のメモリにアクセスすると、ハードウェアはセグメンテーションフォールトを認識し、その状態をカーネルに警告します。カーネルは自分自身のデータ構造でそのページを調べ、そこにゼロページがあるはずであることを発見し、ゼロページをマッピングし(おそらく最初にページキャッシュからページを退避させる)、割り込みから戻ります。カーネルの操作は完全に透過的です(カーネルがその仕事をする間の短い遅延を除いて)。
この最適化により、システムコールは非常に迅速に戻ることができ、最も重要なことは、マッピングが行われる際にプロセスにコミットされるリソースを回避することができます。これにより、通常では決して必要としないような大きなバッファを、大量のメモリを消費することなく確保することができます。
ですから、メモリイーターをプログラムする場合は、割り当てたメモリで実際に何かをする必要があります。そのためには、コードに一行加えるだけでいいのです。
int eat_kilobyte()
{
if (memory == NULL)
memory = malloc(1024);
else
memory = realloc(memory, (eaten_memory * 1024) + 1024);
if (memory == NULL)
{
return 1;
}
else
{
//Force the kernel to map the containing memory page.
((char*)memory)[1024*eaten_memory] = 42;
eaten_memory++;
return 0;
}
}
なお、各ページ(X86では4096バイトを含む)内の1バイトに書き込めば完全に事足りる。これは、カーネルからプロセスへのすべてのメモリ割り当てがメモリページ粒度で行われるためで、ひいてはそれより小さい粒度でのページングを許さないハードウェアのためでもあります。
関連
-
[解決済み】ENOENTが「そのようなファイルやディレクトリはありません」という意味であるのはなぜですか?
-
警告:代入がキャストなしで整数からポインタを作成する場合の修正方法に関する警告
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] 配列の場合、なぜ a[5] == 5[a] になるのでしょうか?
-
[解決済み] 難読化Cコードコンテスト2006。sykes2.cの解説をお願いします。
-
[解決済み] プログラム終了前にmallocの後にfreeをしないと本当に何が起こるのか?
-
[解決済み] printfにおけるdoubleの正しい書式指定子
-
[解決済み] Pythonで明示的にメモリを解放するにはどうしたらいいですか?
-
[解決済み】なぜこれらのコンストラクトはプリインクリメントとポストインクリメントを使用して未定義の動作をしているのでしょうか?
-
[解決済み] コンパイル時にメモリを確保する」の本当の意味とは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
#137: 式は変更可能なlvalueでなければならない問題 // 文字列配列の代入問題
-
関数 'malloc' の暗黙の宣言に対する解決策
-
未定義の `__isoc99_sscanf' への参照
-
[解決済み] stdinとSTDIN_FILENOの違いは何ですか?
-
[解決済み] C 言語で const char* を char* に変換するには?
-
[解決済み] 配列のすべてのメンバーを同じ値で初期化するには?
-
[解決済み] 難読化Cコードコンテスト2006。sykes2.cの解説をお願いします。
-
[解決済み] printfにおけるdoubleの正しい書式指定子
-
[解決済み] .aファイル、.soファイルとは何ですか?
-
[解決済み] C言語の構造体(CGRectやCGPointなど)をNSLog化することは可能ですか?