我可以依靠malloc返回NULL吗?

我在Unix系统上读到,即使内存实际上不可用, malloc也可以返回一个非NULL指针,稍后尝试使用内存将触发一个错误。 由于我不能通过检查NULL来捕捉这样的错误,我想知道检查NULL是多么的有用吗?

在一个相关的说明中,Herb Sutter说,处理C ++内存错误是徒劳的,因为在实际发生exception之前,系统就会进入分页的痉挛状态。 这也适用于malloc吗?

引用Linux手册 :

默认情况下,Linux遵循乐观的内存分配策略。 这意味着当malloc()返回非NULL ,不能保证内存真的可用。 这是一个非常糟糕的错误。 如果事实certificate系统内存不足,一个或多个进程将被臭名昭着的OOM杀手杀死。 如果在不希望突然丢失一些随机选取的进程的情况下使用Linux,而且内核版本足够近,则可以使用如下命令closures这种过度使用行为:

 # echo 2 > /proc/sys/vm/overcommit_memory 

您应该检查是否返回NULL ,特别是在32位系统上,因为进程地址空间可能会在RAM之前耗尽:例如在32位Linux上,用户进程可能具有2G-3G的可用地址空间,而不是超过4G的总RAM。 在64位系统上,检查malloc返回码可能没有用处,但无论如何都可能被认为是最佳实践,它确实使您的程序更具可移植性。 而且,请记住,取消引用空指针肯定会杀死你的进程; 与此相比,一些交换可能不会有太大的伤害。

如果malloc在尝试分配less量内存时碰巧返回NULL ,那么在尝试从错误状态中恢复时必须谨慎,因为任何后续的malloc都可能会失败,直到有足够的内存可用。

默认的C ++操作符new通常是malloc()使用的相同分配机制的包装。

在Linux上,如果由于内核的重定位策略而导致内存不足,你确实可以不依靠malloc返回NULL ,但是你仍然应该检查它,因为在某些情况下, malloc 返回NULL ,例如,当你要求更多的内存在机器中总共可用。 Linux malloc(3)联机帮助页调用了“非常糟糕的错误”,并包含关于如何closures它的build议。

我从来没有听说过其他Unix变种也会发生这种行为。

至于“寻呼痉挛”,这取决于机器设置。 例如,我倾向于不在笔记本电脑的Linux安装上设置交换分区,因为您担心的确切行为可能会导致硬盘死机。 我仍然会喜欢我运行的C / C ++程序来检查malloc返回值,给出相应的错误消息,并在可能的时候自行清理。

检查malloc的返回对你自己来说并没有什么帮助,使你的分配更安全或者更less出错。 如果这是您实施的唯一的testing,它甚至可能是一个陷阱。

当用0的参数调用时,标准允许malloc返回一个唯一的地址,这个地址不是一个空指针,而你没有权限访问。 所以,如果你只是testing返回值是0还是不testingmalloccalloc或者realloc的参数,你可能会在稍后遇到一个segfault。

这种错误情况(内存耗尽)在“托pipe”环境中相当罕见。 通常情况下,在你遇到这种错误之前,你早已陷入困境。 (但是,如果你正在编写运行时库,是一个内核黑客或火箭build设者,这是不同的,那么testing是非常有意义的。)

然后,人们倾向于用错误条件的复杂捕获来修饰他们的代码,这些错误条件跨越了几行,做了一些类似的事情,这可能会影响代码的可读性。

我认为这个“检查malloc的回报”被高估了,有时甚至很顽固地辩护。 其他的事情更重要:

  • 总是初始化variables。 对于指针variables这是至关重要的,让程序在事情变得糟糕之前很好地崩溃。 struct未初始化的指针成员是很难find的错误的重要原因。
  • 总是检查malloc和Co.的参数,如果这是一个像sizof toto这样的编译时常sizof toto那么不会有问题,但总是要确保你的向量分配正确地处理了零情况。

检查malloc返回的一个简单的事情就是用memset(malloc(n), 0, 1)来包装它。 这只是在第一个字节中写入一个0 ,并且如果malloc出错或者n开头为0 ,则会崩溃。

从另一个angular度来看待这个问题:

malloc可以返回一个非NULL指针,即使内存不是真正可用”并不意味着它总是返回非NULL。 有可能(而且会)是NULL返回(如其他人已经说过的),所以这个检查是必要的。