程序在new抛出bad_alloc之前被终止

Program gets aborted before new throws bad_alloc

本文关键字:终止 alloc new 抛出 bad 程序      更新时间:2023-10-16

下面是一个小的c++程序,在"new"抛出异常之前,它显然会在许多情况下被终止:

int main(){
   try{
      while(true)
         new char[2];
   }
   catch(...){
      while(true);
   }
}

该程序首先使用MinGW/g++ 4.6.1编译,然后通过shell在32位Windows 7系统上执行。当时没有其他重要的程序(就内存/CPU消耗而言)正在运行。程序在进入捕获块之前终止。在Linux (Debian 7.3, gcc/c++ 4.7.2, 24GB内存)下编译和运行程序时,程序的行为类似。(在catch块中进行无限循环的原因是为了避免可能抛出异常的任何东西—特别是I/o。)当在Windows系统上两次启动程序时,发生了一些令人惊讶的事情(至少对我来说):如果程序(几乎)同时在两个不同的shell中启动,那么在抛出new-exception之前,两个进程都不会终止。同样出乎我意料的是,观察到只有适度扩大分配的内存块的大小(通过将第四行中的"2"替换为"9")才能使过早终止在Windows系统上消失。在Linux机器上,需要更大的扩展来避免终止:大约。每个块需要40,000,000字节来防止终止。

我在这里错过了什么?这是相关操作系统的正常/预期行为吗?如果是这样,这是否会削弱异常的有用性——至少在动态分配失败的情况下是这样?是否可以修改操作系统设置(由用户)以防止这种过早终止?最后,关于"严肃的"应用程序:在什么情况下(从动态内存分配开始)我不得不担心我的应用程序会被操作系统突然终止?

这是相关操作系统的正常/预期行为吗?

是的,它被称为"过度提交"或"延迟分配"。Linux(我认为是Windows,但我从未为Windows操作系统编程)会在您请求时为进程分配虚拟内存,但在您访问它之前不会尝试分配物理内存。在这个点上,如果没有可用的RAM或交换空间,程序将失败。或者,至少在Linux的情况下,其他进程可能会被随机杀死,以便您可以掠夺它们的内存。

请注意,当执行这样的小分配时,进程将分配较大的块并将它们放在堆中;因此,分配的内存通常会立即被访问。一个大的分配将直接从操作系统分配,所以你的测试程序不会访问内存-这就是为什么你观察到程序没有中止当你分配大块。

如果是这样,这是否会削弱异常的有用性——至少在动态分配失败的情况下是这样?

是的,它确实是。

是否可以修改操作系统设置(由用户)以防止这种过早终止?

在Linux上,有一个系统变量来控制超额提交策略:

echo 2 > /proc/sys/vm/overcommit_memory

值2表示永远不要过度提交——如果分配请求的内存超过当前未提交的内存加上交换空间,那么分配将失败。1意味着分配永远不会失败。0(默认值)表示猜测分配请求是否合理。

我不知道Windows是否同样可配置