6
int *p;
while(true)
{
 p = new int;
}

由于内存空间不足,这段代码不应该崩溃。我已经尝试打印出 p 的值,即 p 的内存地址,它似乎在增加,但没有崩溃。

为什么会这样?

4

6 回答 6

9

这种解决方案就像在以每小时 1 英里的速度行驶时试图在街上的电线杆上撞车。它最终会发生,但如果你想要快速的结果,你需要加快速度。

int *p;
while (true) { 
  p = new int[1024*1024*1024];
}

不过,我的答案是基于您的代码库,使用标准 STL 分配器会引发内存分配失败。还有其他可用的分配器,它们只是NULL在分配失败时返回。这种类型的分配器永远不会在此代码中崩溃,因为失败的分配不被认为是致命的。您必须检查分配的返回NULL以检测错误。

另一个警告是,如果您在 64 位系统上运行,由于地址空间大小的增加,崩溃可能需要相当长的时间。电话民意调查不是在街上,而是在全国各地。

于 2010-10-25T17:51:38.657 回答
9

看起来你在看到崩溃之前不会关闭这个问题:)

在类 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
于 2010-10-25T18:03:53.977 回答
7

小块内存的多次分配比一次大分配要慢。例如,分配 4 个字节 100 万次比分配 100 万个字节 4 次要花费更多的时间。

尝试一次分配更大的内存块:

int *p;
while(true)
{
 p = new int[1024*1024];
}
于 2010-10-25T17:49:05.347 回答
4

你没有等待足够长的时间。

[如果您想查看它的进展情况,请在每 1000000 个循环或类似的东西上添加一些输出。它最终失败。]

于 2010-10-25T17:47:14.363 回答
1

我在想编译器正在做一些优化,并没有真正分配内存。我运行了上述示例(使用 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% 确定)

于 2010-11-03T13:08:14.697 回答
1

另一种可能性:大多数操作系统将执行乐观分配。当您 malloc 时,例如 500 MB,在您的程序实际尝试读取或写入它之前,实际上可能不会保留该内存。

特别是 Linux 因过度承诺内存而臭名昭著,然后依靠 OOM(内存不足)杀手来打击试图收集内核承诺的进程。

于 2010-11-03T14:49:18.947 回答