int *p;
while(true)
{
p = new int;
}
由于内存空间不足,这段代码不应该崩溃。我已经尝试打印出 p 的值,即 p 的内存地址,它似乎在增加,但没有崩溃。
为什么会这样?
int *p;
while(true)
{
p = new int;
}
由于内存空间不足,这段代码不应该崩溃。我已经尝试打印出 p 的值,即 p 的内存地址,它似乎在增加,但没有崩溃。
为什么会这样?
这种解决方案就像在以每小时 1 英里的速度行驶时试图在街上的电线杆上撞车。它最终会发生,但如果你想要快速的结果,你需要加快速度。
int *p;
while (true) {
p = new int[1024*1024*1024];
}
不过,我的答案是基于您的代码库,使用标准 STL 分配器会引发内存分配失败。还有其他可用的分配器,它们只是NULL
在分配失败时返回。这种类型的分配器永远不会在此代码中崩溃,因为失败的分配不被认为是致命的。您必须检查分配的返回NULL
以检测错误。
另一个警告是,如果您在 64 位系统上运行,由于地址空间大小的增加,崩溃可能需要相当长的时间。电话民意调查不是在街上,而是在全国各地。
看起来你在看到崩溃之前不会关闭这个问题:)
在类 Unix 操作系统上,您可以使用ulimit命令限制进程可用的虚拟内存量。通过将 VM 设置为 1MB,我能够在大约 5 秒内看到所需的结果:
$ ulimit -v $((1024*1024)) # set max VM available to process to 1 MB
$ ulimit -v # check it.
1048576
$ time ./a.out # time your executable.
terminate called after throwing an instance of 'St9bad_alloc'
what(): std::bad_alloc
Aborted
real 0m5.502s
user 0m4.240s
sys 0m1.108s
小块内存的多次分配比一次大分配要慢。例如,分配 4 个字节 100 万次比分配 100 万个字节 4 次要花费更多的时间。
尝试一次分配更大的内存块:
int *p;
while(true)
{
p = new int[1024*1024];
}
你没有等待足够长的时间。
[如果您想查看它的进展情况,请在每 1000000 个循环或类似的东西上添加一些输出。它最终会失败。]
我在想编译器正在做一些优化,并没有真正分配内存。我运行了上述示例(使用 valgrind)几次,发现即使在哪里分配,所有哪里都是 0 字节内存。
试试这个,你的程序会被杀死(至少在 unix 上):
#include <cstdio>
int main() {
int *p;
while (true) {
p = new int[1024*1024];
p[0] = 0;
printf("%p\n",p);
for(unsigned j = 1; j < 1024*1024; j++) {
p[j] = p[j-1] + 1;
}
}
return 0;
}
您看到的唯一区别是我使用分配的内存。
所以,它并没有真正崩溃,因为我猜操作系统只是通过杀死它来防止进程崩溃(对此不是 100% 确定)
另一种可能性:大多数操作系统将执行乐观分配。当您 malloc 时,例如 500 MB,在您的程序实际尝试读取或写入它之前,实际上可能不会保留该内存。
特别是 Linux 因过度承诺内存而臭名昭著,然后依靠 OOM(内存不足)杀手来打击试图收集内核承诺的进程。