linux上c++内存分配new (nothrow)失败时该怎么做

what to do upon failure of memory allocation new (nothrow) in c++ on linux

本文关键字:失败 nothrow c++ 内存 分配 new linux      更新时间:2023-10-16

在no-exception上下文中,我看到几个帖子说

Thing* t = new(std::nothrow) Thing; // returns NULL on failure
if (!t) {
  // allocation failure
}

如何检查内存分配失败与新的操作符?

如何找出返回值,如果我的c++"新"内存分配失败?

我相信这是他们从c++标准中得到的声明,如引用:

如果分配函数声明为非抛出类型异常规范,它返回null以指示失败否则分配存储空间和非空指针。

然而,由Herb Sutterhttp://www.gotw.ca/publications/mill16.htm

linux会过度使用内存,这是不符合c++标准的。也就是说,检查null与Linux系统无关。"new"的成功与否取决于进程是否被linux杀死。

那么我们能做什么呢?似乎没有办法检查失败。

[UPDATE] about linux overcommit: overcommit_memory

0 -默认设置。内核执行启发式内存通过估计可用内存量和明显无效的失败请求。不幸的是,自内存分配使用启发式算法,而不是精确算法,这种设置有时允许系统上的可用内存被占用过载。

Linux默认不复用。真正的解决方案是不要这样配置它。

鱼和熊掌不可兼得。如果您在默认状态下使用linux(不过度提交),那么检测内存分配错误是没有问题的。如果你将它配置为过度提交,那么你需要设计你的程序,使它不会耗尽内存(即确保有比你的程序将尝试分配更多的可用内存)或重新构建你的程序,使它在失败之前终止,从而产生不必要的后果(例如,不销毁对象和保存状态到文件)。 然而

…如果您坚持要将系统配置为过度提交,那么Herb在该链接中暗示了解决方案。

本质上,有必要重新组织你的程序,以便所有的动态内存分配都是预先完成的。

  p = new (nothrow) Thing;
  if (p != NULL)
      touch(p);
  else
      terminate_with_prejudice()

其中touch()确保在linux下提交内存分配(草本的页面描述了如何做到这一点)。

或者,用于抛出new;

  try
  {
        p = new Thing;
        touch(p);
  }
  catch (...)
  {
      terminate_with_prejudice()
  }

如果发生故障,则程序将在任何系统上异常终止。如果在启动前完成此操作,则不会造成任何损坏(除非程序未启动)。

区别在于故障在不同系统上的发生方式。对于这两种形式,linux系统将始终调用touch(),并且程序将在出现故障时异常执行。在非linux系统上,terminate_with_prejudice()将在故障时被调用。无论哪种方式,程序都将停止执行。

异常的捕获是可选的,但我这样做是为了使两个代码示例相等(至少,在任何选定的系统上)。

这里的问题(没有双关语的意思)是,重新构建整个程序以避免在启动后向主机系统请求内存是很重要的。不这样做将意味着以同样的方式终止,但不能始终保证程序可以执行任何必要的清理。