2

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

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

例如

如何使用 new 运算符检查内存分配失败?

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

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

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

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

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

所以,我们能做些什么?似乎没有办法检查故障。

[更新] 关于 linux overcommit:overcommit_memory

0 — 默认设置。内核通过估计可用内存量和明显无效的失败请求来执行启发式内存过度使用处理。不幸的是,由于内存是使用启发式而不是精确算法分配的,因此此设置有时会导致系统上的可用内存过载。

4

1 回答 1

1

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

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

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

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

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

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

或者,用于抛出新的;

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

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

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

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

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

于 2015-07-21T13:17:57.680 回答