あなたの元の問題は malloc
だったと思います 要求されたメモリをシステムに割り当てることができませんでした。
これが発生した理由は、システムに固有です。
プロセスがロードされると、プロセスのシステム ブレーク ポイントである特定のアドレスまでメモリが割り当てられます。そのアドレスを超えると、メモリはプロセスに対してマップ解除されます。そのため、プロセスが「ブレーク」ポイントに「ヒット」すると、システムからより多くのメモリを要求します。これを行う 1 つの方法は、システム コール sbrk を使用することです。
malloc
ボンネットの下でそれを行いますが、システムでは何らかの理由で失敗しました。
これには、たとえば次のような多くの理由が考えられます。
1) Linux では最大メモリ サイズに制限があると思います。 ulimit
だと思います そしておそらくあなたはそれを打ちました。制限されていないか確認する
2) システムの負荷が高すぎる可能性があります
3) あなたのプログラムは不適切なメモリ管理を行っており、断片化したメモリになってしまうので malloc
要求したチャンク サイズを取得できません。
4) あなたのプログラムは malloc
を壊しています 内部データ構造、つまり不適切なポインターの使用
など
ヒープは通常、アーキテクチャ上のアドレス指定可能な仮想メモリと同じ大きさです。
ulimit -a
でシステムの現在の制限を確認する必要があります コマンドを実行して、この行を最大 memory size (kbytes, -m) 3008828
シークします 、~3.5 GiB の RAM を搭載した OpenSuse 11.4 x86_64 のこの行は、プロセスごとに約 3GB の RAM があることを示しています。
次に、この簡単なプログラムを使用してシステムを実際にテストし、プロセスごとに使用可能な最大メモリをチェックできます。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char* argv[]){
size_t oneHundredMiB=100*1048576;
size_t maxMemMiB=0;
void *memPointer = NULL;
do{
if(memPointer != NULL){
printf("Max Tested Memory = %zi\n",maxMemMiB);
memset(memPointer,0,maxMemMiB);
free(memPointer);
}
maxMemMiB+=oneHundredMiB;
memPointer=malloc(maxMemMiB);
}while(memPointer != NULL);
printf("Max Usable Memory aprox = %zi\n",maxMemMiB-oneHundredMiB);
return 0;
}
このプログラムは、100MiB 単位でメモリを取得し、現在割り当てられているメモリを提示し、それに 0 を割り当ててから、メモリを解放します。システムがそれ以上のメモリを提供できない場合、NULL を返し、RAM の最終的な最大使用可能量を表示します。
警告は、システムが最終段階で大量のメモリをスワップし始めることです。システム構成によっては、カーネルがいくつかのプロセスを強制終了することを決定する場合があります。私は 100 MiB のインクリメントを使用しているため、一部のアプリとシステムには余裕があります。クラッシュさせたくないものはすべて閉じる必要があります。
そうは言っても。これを書いている私のシステムでは、何もクラッシュしませんでした。そして、上記のプログラムは ulimit -a
とほとんど同じではないことを報告しています .違いは、実際にメモリをテストし、memset()
を使用してテストしたことです。 メモリが与えられ、使用されたことを確認しました。
256 MiB の RAM と 400MiB のスワップを備えた Ubuntu 10.04x86 VM での比較では、ulimit レポートは memory size (kbytes, -m) unlimited
でした。 私の小さなプログラムは 524.288.000 バイトを報告しました。これはおおよそ RAM とスワップを合わせたもので、他のソフトウェアとカーネルが使用する RAM を差し引いています。
編集:Adam Zalcman が書いたように、ulimit -m
新しい 2.6 以降の Linux カーネルでは受け入れられなくなったので、訂正します。しかし ulimit -v
光栄です。実際の結果を得るには、-m を -v に置き換え、virtual memory (kbytes, -v) 4515440
を探す必要があります。 .私の小さなユーティリティが報告したものと一致する -m 値が私の suse ボックスにあったのは単なる偶然のようです。これはカーネルによって割り当てられる仮想メモリであることを覚えておく必要があります。物理 RAM が不十分な場合、それを補うためにスワップ領域が必要になります。
プロセスやシステムに影響を与えずに利用可能な物理 RAM の量を知りたい場合は、
long total_available_ram =sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) ;
これにより、キャッシュとバッファ メモリが除外されるため、この数値は実際に使用可能なメモリよりもはるかに小さくなる可能性があります。 OS キャッシュは静かに大きくなり、削除によって必要な追加メモリが提供される場合がありますが、それはカーネルによって処理されます。
ヒープとメモリの管理は、C ライブラリ (おそらく glibc) によって提供される機能です。 malloc()
を実行するたびに、ヒープを維持し、メモリのチャンクを返します .ヒープ サイズの制限はわかりません。ヒープで利用可能なメモリよりも多くのメモリを要求するたびに、カーネルにさらに多くのメモリを要求します (sbrk()
を使用) または mmap()
).
デフォルトでは、カーネルはほとんどの場合、要求されたときに追加のメモリを提供します。つまり、malloc()
常に有効なアドレスを返します。カーネルが実際にわざわざページを見つけようとするのは、割り当てられたページを初めて参照するときだけです。それが手渡せないことが判明した場合、それは特定の基準に従って badness と呼ばれる OOM キラーを実行します (これには、プロセスとその子の仮想メモリ サイズ、nice レベル、全体の実行時間などが含まれます) 犠牲者を選択し、SIGTERM
を送信します。 .このメモリ管理手法はオーバーコミットと呼ばれ、/proc/sys/vm/overcommit_memory
のときにカーネルによって使用されます。 0 または 1 です。詳細については、カーネル ドキュメントの overcommit-accounting を参照してください。
/proc/sys/vm/overcommit_memory
に 2 を書き込む オーバーコミットを無効にすることができます。これを行うと、カーネルは約束する前に実際にメモリがあるかどうかを確認します。これは malloc()
になります 利用可能なメモリがそれ以上ない場合は NULL を返します。
setrlimit()
でプロセスが割り当てることができる仮想メモリに制限を設定することもできます と RLIMIT_AS
または ulimit -v
指図。上記のオーバーコミット設定に関係なく、プロセスが制限よりも多くのメモリを割り当てようとすると、カーネルはそれを拒否し、malloc()
NULL を返します。最新の Linux カーネル (2.6.x シリーズ全体を含む) では、常駐サイズ (setrlimit()
) の制限に注意してください。 RLIMIT_RSS
で または ulimit -m
コマンド) は無効です。
以下のセッションは、カーネル 2.6.32、RAM 4GB、スワップ 8GB で実行されました。
$ cat bigmem.c
#include <stdlib.h>
#include <stdio.h>
int main() {
int i = 0;
for (; i < 13*1024; i++) {
void* p = malloc(1024*1024);
if (p == NULL) {
fprintf(stderr, "malloc() returned NULL on %dth request\n", i);
return 1;
}
}
printf("Allocated it all\n");
return 0;
}
$ cc -o bigmem bigmem.c
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ sudo bash -c "echo 2 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
2
$ ./bigmem
malloc() returned NULL on 8519th request
$ sudo bash -c "echo 0 > /proc/sys/vm/overcommit_memory"
$ cat /proc/sys/vm/overcommit_memory
0
$ ./bigmem
Allocated it all
$ ulimit -v $(( 1024*1024 ))
$ ./bigmem
malloc() returned NULL on 1026th request
$
上記の例では、スワッピングまたは OOM キルが発生することはありませんが、プロセスが割り当てられたすべてのメモリに実際にアクセスしようとすると、これは大幅に変化します。
質問に直接答えるには:ulimit -v
で仮想メモリ制限を明示的に設定していない限り コマンドを実行すると、マシンの物理リソースまたはアドレス空間の論理制限 (32 ビット システムに関連) 以外にヒープ サイズの制限はありません。 glibc はヒープにメモリを割り当て続け、ヒープが大きくなるにつれてカーネルに要求を増やします。最終的に、すべての物理メモリが使い果たされると、スワップがうまくいかなくなる可能性があります。スワップ スペースが使い果たされると、ランダムなプロセスがカーネルの OOM キラーによって強制終了されます。
ただし、メモリの割り当ては、空きメモリの不足、断片化、構成された制限への到達以外の多くの理由で失敗する可能性があることに注意してください。 sbrk()
と mmap()
glib のアロケーターによって使用される呼び出しには、独自の失敗があります。プログラム ブレークが、既に割り当てられている別のアドレス (たとえば、共有メモリまたは以前に mmap()
でマップされたページ) に到達した ) またはプロセスのメモリ マッピングの最大数を超えました。