通常、最新のマシンでは、仮想アドレス空間が不足しているため失敗します。2/3 GB を超えるメモリ1を割り当てようとする 32 ビット プロセスがある場合、割り当てを満たす物理 RAM (またはページング ファイル) があっても、単に仮想アドレス空間にスペースがありません。そのような新しく割り当てられたメモリをマップします。
別の (同様の) 状況は、仮想アドレス空間が大幅に断片化されている場合に発生し、連続したアドレスが十分にないために割り当てが失敗します。
また、メモリ不足が発生する可能性があり、実際に先週そのような状況に陥りました。ただし、この場合、いくつかのオペレーティング システム (特に Linux) は NULL を返しません。Linux は、まだコミットされていないメモリ領域へのポインターを喜んで提供し、プログラムが書き込みを試みるときに実際にそれを割り当てます。その時点で十分なメモリがない場合、カーネルはメモリを大量に消費するプロセスを強制終了してメモリを解放しようとします (この動作の例外は、RAM とスワップ パーティションの全容量を超えて割り当てようとした場合のようです)。 - そのような場合は、NULL
前払いを取得します)。
malloc から NULL を取得するもう 1 つの原因は、プロセスに対して OS によって適用される制限が原因である可能性があります。たとえば、このコードを実行しようとすると
#include <cstdlib>
#include <iostream>
#include <limits>
void mallocbsearch(std::size_t lower, std::size_t upper)
{
std::cout<<"["<<lower<<", "<<upper<<"]\n";
if(upper-lower<=1)
{
std::cout<<"Found! "<<lower<<"\n";
return;
}
std::size_t mid=lower+(upper-lower)/2;
void *ptr=std::malloc(mid);
if(ptr)
{
free(ptr);
mallocbsearch(mid, upper);
}
else
mallocbsearch(lower, mid);
}
int main()
{
mallocbsearch(0, std::numeric_limits<std::size_t>::max());
return 0;
}
Ideoneでは、最大割り当てサイズが約 530 MB であることがわかります。これはおそらくsetrlimit
(Windows にも同様のメカニズムが存在します) によって強制される制限です。
- OS によって異なり、多くの場合、構成できます。32 ビット プロセスの仮想アドレス空間の合計は 4 GB ですが、現在の主流のすべての OS では、その大部分 (デフォルト設定の 32 ビット Windows では上位 2 GB) がカーネル データ用に予約されています。