26

我一直在阅读 Linux 上的内存不足情况,手册页中的以下段落让我思考:

默认情况下,Linux 遵循乐观的内存分配策略。这意味着当 malloc() 返回非 NULL 时,不能保证内存确实可用。这是一个非常糟糕的错误。如果发现系统内存不足,一个或多个进程将被臭名昭著的 OOM 杀手杀死。[...]

考虑到 operator new 实现最终会在某个时候调用 malloc,是否有任何保证 new 会在 Linux 上实际抛出?如果没有,如何处理这种明显无法检测到的错误情况?

4

5 回答 5

21

这取决于; 您可以使用 vm.overcommit_memory配置内核的过度使用设置。

Herb Sutter 几年前讨论过这种行为实际上是如何不符合 C++ 标准的

“在某些操作系统上,包括特别是Linux,内存分配总是成功的。句号。即使请求的内存真的不可用,分配怎么能总是成功?原因是分配本身只是记录了对内存的请求;在幕后,(物理或虚拟)内存实际上并没有真正提交给请求进程,具有真正的后备存储,直到内存被实际使用。

“请注意,如果 new 直接使用操作系统的设施,那么 new 将始终成功,但任何后来的无辜代码(如 buf[100] = 'c'; 可能会抛出或失败或停止。从标准 C++ 的角度来看,这两种效果不符合标准,因为 C++ 标准要求如果 new 不能提交足够的内存,它必须失败(这不会),并且像 buf[100] = 'c' 这样的代码不应抛出异常或以其他方式失败(这可能)。”

于 2009-10-31T21:18:53.157 回答
9

你无法在你的软件中处理它,纯粹而简单。

对于您的应用程序,您将收到一个完全有效的指针。一旦您尝试访问它,它将在内核中生成页面错误,内核将尝试为它分配一个物理页面,如果它不能......繁荣。

但是正如您所看到的,所有这些都发生在内核内部,您的应用程序看不到这一点。如果它是一个关键系统,您可以在系统上一起禁用过度使用。

于 2009-10-31T21:23:22.700 回答
4

我认为 malloc 仍然可以返回 NULL。原因是可用系统内存(RAM + 交换)和进程地址空间中的数量之间存在差异。

例如,如果您在标准 x86 linux 上向 malloc 请求 3GB 内存,它肯定会返回 NULL,因为考虑到用户空间应用程序的内存量,这是不可能的。

于 2009-10-31T21:20:08.130 回答
3

如果我错了,请原谅我,但是尝试将分配的内存归零是否足以保证您拥有所需的每一个字节?或者甚至只是写入最后一个字节,如果内存不是你的,它会抛出异常吗?

如果这是真的,您可以尝试写入内存的最后一个(也是第一个?)字节,看看它是否工作正常,如果不是,您可以从 malloc 返回 null。

于 2009-10-31T22:12:41.717 回答
1

是的,有一个保证 new 最终会抛出。无论是否过度使用,地址空间的数量都是有限的。因此,如果您继续分配内存,迟早您会用完地址空间,并且 new 将被迫抛出。

于 2009-10-31T21:40:54.053 回答