我读到在Unix系统上,即使内存实际上不可用,malloc
也可以返回非NULL指针,并且稍后尝试使用内存将触发错误。由于我无法通过检查NULL来捕获这样的错误,我想知道检查NULL是否有用呢?
在相关的说明中,Herb Sutter说处理C ++内存错误是徒劳的,因为系统会在实际发生异常之前很久就会出现分页痉挛。这是否也适用于malloc
?
答案 0 :(得分:32)
默认情况下,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
但是不测试malloc
,calloc
或realloc
的参数,则可能会在以后遇到段错误。
在“托管”环境中,此错误情况(内存耗尽)非常少见。通常你在遇到这种错误之前很久就遇到了麻烦。 (但是如果你正在编写运行时库,那么这是一个内核黑客或火箭构建器,这是不同的,并且测试非常有意义。)
然后人们倾向于使用复杂的错误条件捕获它们的代码,这些错误条件跨越多行,执行perror
以及类似的东西,这会对代码的可读性产生影响。
我认为这种“检查malloc
的回归”被高估了,有时甚至是非常粗俗的辩护。其他事情更为重要:
struct
中未初始化的指针成员是难以找到的错误的重要原因。 malloc
和Co.的参数
像sizof toto
这样的时间常数不会有问题,但是
始终确保您的矢量分配正确处理零情况。检查malloc
的返回是一件容易的事情,就是用memset(malloc(n), 0, 1)
之类的东西来包装它。这只会在第一个字节中写入0
,如果malloc
出现错误或n
0
为{{1}},则会很快崩溃。
答案 3 :(得分:1)
从另一个角度来看这个:
“malloc
可以返回非NULL指针,即使内存实际上不可用”并不意味着它总是返回非NULL。可能(并且将来)会返回NULL(正如其他人已经说过的那样),所以这个检查是必要的。