我可以依赖malloc返回NULL吗?

时间:2011-10-30 21:13:04

标签: c memory error-handling malloc

我读到在Unix系统上,即使内存实际上不可用,malloc也可以返回非NULL指针,并且稍后尝试使用内存将触发错误。由于我无法通过检查NULL来捕获这样的错误,我想知道检查NULL是否有用呢?

在相关的说明中,Herb Sutter说处理C ++内存错误是徒劳的,因为系统会在实际发生异常之前很久就会出现分页痉挛。这是否也适用于malloc

4 个答案:

答案 0 :(得分:32)

引用Linux manuals

  

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

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

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

如果malloc碰巧在尝试仅分配少量内存时返回NULL,则在尝试从错误条件中恢复时必须谨慎,因为任何后续malloc也可能会失败,直到有足够的内存可用。

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

答案 1 :(得分:5)

在Linux上,如果由于内核的分配策略而没有足够的内存,你确实不能依赖malloc返回NULL,但你仍然应该检查它,因为在某些情况下{{1} } 返回malloc,例如当你要求的内存总量超过机器中可用的内存时。 Linux NULL联机帮助页将调用过程称为“一个非常糟糕的错误”,并包含有关如何将其关闭的建议。

我从未听说过其他Unix变种中也会出现这种情况。

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

答案 2 :(得分:2)

检查malloc的返回对您自己的帮助不大,使您的分配更安全或更不容易出错。如果这是您实施的唯一测试,它甚至可能是一个陷阱。

当使用0参数调用时,标准允许malloc返回一种唯一的地址,该地址不是空指针,而是您无权访问的地址。因此,如果您只是测试返回值是否为0但是不测试malloccallocrealloc的参数,则可能会在以后遇到段错误。

在“托管”环境中,此错误情况(内存耗尽)非常少见。通常你在遇到这种错误之前很久就遇到了麻烦。 (但是如果你正在编写运行时库,那么这是一个内核黑客或火箭构建器,这是不同的,并且测试非常有意义。)

然后人们倾向于使用复杂的错误条件捕获它们的代码,这些错误条件跨越多行,执行perror以及类似的东西,这会对代码的可读性产生影响。

我认为这种“检查malloc的回归”被高估了,有时甚至是非常粗俗的辩护。其他事情更为重要:

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

检查malloc的返回是一件容易的事情,就是用memset(malloc(n), 0, 1)之类的东西来包装它。这只会在第一个字节中写入0,如果malloc出现错误或n 0为{{1}},则会很快崩溃。

答案 3 :(得分:1)

从另一个角度来看这个:

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