如何检测malloc()函数是否会失败?

3

在我的C程序中,我正试图使用malloc()函数分配一些内存,就像这样:

char *buf = (char *)malloc(size);

但问题在于malloc()总是返回非空指针。即使我试图分配巨大的内存(大小为1E + 13),它仍然会返回一个有效的buf指针。当然,在此之后,程序会崩溃。
但是,如果返回的buf值不为空,我如何检测请求的内存量过大而无法使用呢?
编辑:
在评论中,我看到我的问题可能不够清楚。因此,这是更详细的示例:
unsigned long size = very_large_calculated_value;
char *buf = (char *)malloc(size);
if (buf == NULL) i_know_it_fails;
...

但是Xcode运行这段代码时,无论请求的大小是多少,buf都不会为NULL。所以,程序很快就会崩溃。如果buf不为NULL但明显无法使用,我该如何检测内存分配失败?

编辑:

对于那些将问题标记为重复的人:
问题“如何检测内存分配失败?”没有答案,因为像“更改操作系统中的某些设置”这样的解决方案并不是一个答案——我正在寻求C代码来检测内存分配错误,或者像“无法通过编程实现”这样的东西。

3
当你说“它返回有效的缓冲指针。当然,在此之后程序会崩溃。”时,你的意思是什么?你有可以展示这种行为的代码吗? - dbush
2
标准警告:不要将由malloc等函数返回的void *转换。C语言 不是 C++! - too honest for this site
3
@Jashaszun 一个 void * 可以安全地分配给任何非函数指针或从其接收赋值,而不需要进行强制类型转换。 - dbush
2
@Jashaszun:请阅读标准文档,这就是我添加最后一句的原因。 - too honest for this site
2
@Jashaszun:只需搜索“C11标准”或查看维基百科;它们会链接这样的内容。一旦找到,我就会将该网站加入书签。在 Stack Overflow 上待了几个月后,我认为我现在相当清楚地知道在哪里找到相关章节。该标准实际上并不难理解。 - too honest for this site
显示剩余8条评论
4个回答

3

无法预测内存分配失败,唯一的方法是检查malloc()的返回值是否为null指针。

看起来你的问题实际上是关于内核进行的内存过度承诺。使用它,内核永远不会返回空指针。默认情况下,总是过度承诺。因此,在类似Linux的系统上禁用它,请执行以下操作:

echo 2 > /proc/sys/vm/overcommit_memory

或者您可以使用 sysctl 来执行相同操作:

sysctl vm.overcommit_memory=2

两者等效。

值为2,以确保在所请求的内存超出可用物理内存(加上交换空间)时,malloc将返回空指针。


如果您使用关心/proc并接受这些选项的内核,等等,那么肯定不会受到标签范围的限制(C,XCode)... - Grady Player
@GradyPlayer 即使是不喜欢proc-BSD的人也可以通过sysctl进行某些更改。标签旨在作为相关性的指南。如果所询问的内容清晰明了,无论实际标签是否正确,我都认为回答没有任何问题。如果OP澄清这不是情况,那么我很乐意删除我的答案。 - P.P
@Kibernetik 你可以打开 /proc/sys/vm/overcommit_memory 并写入以下内容:int fd=open("/proc/sys/vm/overcommit_memory", O_WRONLY|O_CREAT|O_TRUNC, 0666); write(fd, "2\n", 2) - P.P
1
@GradyPlayer 这个问题特定于那些过度承诺的系统。因此,解决方案无法移植。唯一符合C标准的方法是检查malloc()的返回值——但这对此处没有帮助。 - P.P
@Kibernetik 如果它被错误地关闭为重复项,那么我可以重新打开它。没有什么是一成不变的。只要解决了问题,您就应该能够发布答案并自行接受它。 - P.P
显示剩余8条评论

2

malloc()总是返回非NULL指针

这并不完全正确。

如果malloc()失败,它将返回NULL。您需要检查malloc()的返回值(指针)是否为NULL,以确保malloc()成功。

引用手册(强调是我的):

malloc()calloc()函数返回一个指向适合任何类型变量的已分配内存的指针。出错时,这些函数返回NULL。 [...]


注意; [接下来的评论]

如果您谈论的是malloc()用于乐观分配技术来返回指针的情况,在这种情况下,没有标准方法来检查预测未来的故障,如果malloc()返回非NULL指针,那么您可以考虑使用calloc()来确保内存的可用性。


5
他正在寻找一种预测故障的方法,因为在某些系统上,即使没有足够的空闲内存,malloc()也会成功(这些系统可能直到你访问内存时才实际占用内存,如果不足够就会出现错误)。 - Dmitri
除非有必要,否则您应引用标准,而不是Linux手册。请注意"xcode"标签。 - too honest for this site
@Olaf 我明白,先生。但这只是一个“琐碎”的案例,大多数时候手册页应该是足够的。 - Sourav Ghosh
阅读链接的段落。对于大小为0的返回值,由实现决定。Linux/glibc和OS-X实际上是两个不同的系统,因此在这里可能会有不同的行为。然而,由于OP现在已经澄清了,他似乎是在寻求乐观分配,而不是调用失败。所以让我们就此解决(暂时;-)。 - too honest for this site
@SouravGhosh 我不确定calloc()更安全...它可能会将整个块链接到单个0的页面并使用写时复制。 - Dmitri
显示剩余11条评论

2
扩展BlueMoon的答案,以下是关于overcommitting的malloc手册所说的内容:
BUGS
默认情况下,Linux遵循一种乐观的内存分配策略。这意味着当malloc()返回非NULL时,并不能保证内存确实可用。这是一个非常严重的错误。如果系统没有足够的内存,那么一个或多个进程将被臭名昭著的OOM killer杀死。在使用Linux的环境中,突然失去一些随机选择的进程并不理想,而且内核版本足够新的情况下,可以使用类似如下命令关闭这种overcommitting行为: # echo 2 > /proc/sys/vm/overcommit_memory 另请参阅内核文档目录中的文件vm/overcommit-accounting和sysctl/vm.txt。

1
OP添加了“XCode”标签,因此我推断这是为OS-X而不是Linux。尽管我怀疑行为是相似的。 - too honest for this site

1
经过多次测试,似乎是Xcode调试问题。结果取决于是否使用断点以及其在代码中的位置。
一般来说,如果删除所有断点,则代码可以正常运行,没有任何问题。但是,如果插入了某些断点(它们在代码中的影响不清楚),则Xcode会变得不稳定,并在内存分配函数后崩溃。

我已经找到了一个编程解决方案来解决这个问题。-- 这似乎并不像这个问题重新开放的令人兴奋的编程解决方案。令人失望... - ad absurdum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接