【问题标题】:what to do upon failure of memory allocation new (nothrow) in c++ on linux在 Linux 上的 C++ 中的内存分配新(nothrow)失败时该怎么办
【发布时间】:2015-07-21 12:33:23
【问题描述】:

在没有例外的情况下,我看到几个帖子说

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

例如

How to check memory allocation failures with new operator?

How to find out the return value if my C++ “new” memory allocation failure?

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

如果分配函数声明为非抛出 exception-specification ,它返回 null 表示失败 否则分配存储空间和非空指针。

然而,赫伯·萨特 http://www.gotw.ca/publications/mill16.htm

linux 会过度使用内存,这不符合 c++ 标准。即,检查 null 与 linux 系统无关。 “new”要么成功,要么失败,进程被 linux 杀死。

那么我们能做些什么呢?似乎没有办法检查故障。

[更新] 关于 linux overcommit:overcommit_memory

0 — 默认设置。内核执行启发式记忆 通过估计可用内存量和 明显无效的失败请求。不幸的是,由于 内存是使用启发式而不是精确算法分配的, 此设置有时可以允许系统上的可用内存 重载。

【问题讨论】:

  • Herb Sutter 的链接页面是 2001 年的。您确定没有更新的文档吗?另外,我是一个说,如果 new/malloc 失败,你会遇到比考虑如何处理更大的问题。只要让应用程序被杀死就可以了。
  • 我不确定,这就是我问的原因,:-)
  • Linux OOM 杀手杀死 其他 进程以使用它们的内存来分配它的进程。正如页面所指出的,malloc 和其他分配函数永远不会因内存过度使用而失败(除非他们这样做,但它会以标准方式处理),因此没有“失败”需要检查。

标签: c++ linux memory-management new-operator nothrow


【解决方案1】:

Linux 默认不会过度使用。真正的解决方案不是这样配置它。

你不能一边吃蛋糕一边吃。如果您在默认状态下使用 linux(不是过度使用),则检测内存分配错误没有问题。如果您将其配置为过度使用,那么您需要设计您的程序以使其不会耗尽内存(即确保有比您的程序尝试分配的内存更多的可用内存)或重新构建您的程序以使其在失败之前终止产生不必要的后果(例如,不破坏对象并将状态保存到文件中)。

但是......如果您坚持将系统配置为过度使用,那么 Herb 会在该链接中暗示解决方案。

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

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

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

或者,用于抛出新的;

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

如果发生故障,则程序将在任何系统上异常终止。如果这是在启动之前完成的,则不会造成任何损坏(除了程序未启动所暗示的)。

不同之处在于故障在不同系统上的发生方式。使用这两种形式,linux系统总是会调用touch(),并且程序会在失败时异常执行。在非 linux 系统上,terminate_with_prejudice() 将在失败时调用。无论哪种方式,程序都将停止执行。

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

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

【讨论】:

  • 彼得,感谢您的 cmets。但正如我从 linux 手册中引用的那样,即使在默认设置下可用的内存也可能会过载。另外,“触摸”不是检测的方式,它只是授予真正分配的内存,使用时我们不会有惊喜。
  • 我意识到touch() 不是一种检测方法。我的观点是没有办法检测,解决方案是设计/配置并避免关注。您引用的那个“linux 手册”是针对特定发行版的——大概是一个配置为目标性能的发行版,即使这意味着偶尔会出现故障。
猜你喜欢
  • 1970-01-01
  • 2011-03-11
  • 1970-01-01
  • 1970-01-01
  • 2013-06-16
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多