我可以依靠malloc返回NULL吗?
我在Unix系统上读到,即使内存实际上不可用, malloc
也可以返回一个非NULL指针,并且稍后尝试使用内存会触发错误。 由于我无法通过检查NULL来捕捉这样的错误,我不知道检查NULL是多么有用吗?
在相关说明中,Herb Sutter说,处理C ++内存错误是徒劳的,因为在实际发生异常之前系统会长期处于分页痉挛状态。 这也适用于malloc
吗?
引用Linux手册:
默认情况下,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()
使用的相同分配机制的包装。
在Linux上,如果由于内核的重定位策略而导致内存不足,您确实可以不依赖malloc
返回NULL
,但是您仍然应该检查它,因为在某些情况下, malloc
将返回NULL
,例如,当您询问内存比在机器中总共可用。 Linux malloc(3)
联机帮助页调用了“非常糟糕的错误”,并包含关于如何关闭该错误的建议。
我从来没有听说过其他Unix变体中也会发生这种行为。
至于“寻呼痉挛”,这取决于机器设置。 例如,我倾向于不在笔记本电脑的Linux安装上设置交换分区,因为您担心的确切行为可能会导致硬盘死机。 我仍然会喜欢我运行的C / C ++程序来检查malloc
返回值,给出相应的错误消息,并在可能时自行清理。
检查malloc
的返回对你自己来说并没有多大帮助,使你的分配更安全或者更不容易出错。 如果这是您实施的唯一测试,它甚至可能成为陷阱。
当使用0
的参数调用时,标准允许malloc
返回一个唯一的地址,不是一个空指针,然而你无权访问它。 因此,如果您只测试返回值是否为0
但不测试malloc
, calloc
或realloc
的参数,则可能会稍后再遇到段错误。
这种错误情况(内存耗尽)在“托管”环境中非常罕见。 通常,在你遇到这种错误之前,你早已陷入困境。 (但是,如果你正在编写运行时库,是一个内核黑客或火箭建造者,这是不同的,并且测试非常有意义。)
然后,人们倾向于用复杂的错误条件捕获代码来修饰代码,这些错误条件包含多行代码,执行perror
和类似代码,这可能会影响代码的可读性。
我认为这个“检查malloc
的回报”被高估了很多,有时甚至是很顽固地辩护。 其他事情更重要:
struct
s中未初始化的指针成员是很难找到的错误的重要原因。 malloc
和Co.的参数,如果这是一个像sizof toto
这样的编译时常sizof toto
那么不会有问题,但始终确保向量分配正确处理零个案。 检查malloc
返回的一个简单的事情就是用memset(malloc(n), 0, 1)
来包装它。 这只是在第一个字节中写入0
,并且如果malloc
发生错误或n
以0
开头,则会崩溃。