【问题标题】:How to detect that malloc() function will fail?如何检测 malloc() 函数会失败?
【发布时间】:2015-08-11 16:55:34
【问题描述】:

在我的 C 程序中,我尝试使用 malloc() 函数分配一些内存,如下所示:

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

但问题是 malloc() 总是返回非 NULL 指针。即使我尝试分配大量(size 为 1E+13)内存,它也会返回有效的 buf 指针。当然是在那个程序崩溃之后。

但是,如果返回的 buf 值不为 NULL,我如何检测到请求的内存量太大且不可用?

编辑:

在 cmets 中,我看到我的问题可能不清楚。所以这是一个更扩展的示例:

unsigned long size = very_large_calculated_value;
char *buf = (char *)malloc(size);
if (buf == NULL) i_know_it_fails;
...

但 Xcode 运行此代码,并且 buf 永远不会为 NULL,无论请求的 size 是什么。所以,很快程序就会崩溃。如果 buf 不为 NULL,但显然无法使用,如何检测内存分配失败?

编辑:

致那些将问题标记为重复的人: “我如何检测内存分配失败?”这个问题没有答案,因为像“更改操作系统中的一些设置”这样的解决方案不是答案 - 我要求 C 代码检测内存分配错误,或者类似的东西“不可能以编程方式制作”。

【问题讨论】:

  • 当你说“它返回有效的 buf 指针。当然在那个程序崩溃之后”是什么意思。您是否有表现出这种行为的代码?
  • 标准警告:不要像 malloc 和朋友返回的那样投射 void *。 C 不是 C++!
  • @Jashaszun a void * 可以在没有强制转换的情况下安全地分配给任何非函数指针或从任何非函数指针分配。
  • @Jashaszun:请阅读standard。这就是我添加最后一句话的原因。
  • @Jashaszun:只需搜索“C11 标准”或查看维基百科;他们链接这样的。一旦找到,我就为该网站添加了书签。在 SO 工作了几个月后,我想我现在很清楚在哪里可以找到相关部分。这个标准其实并不难理解。

标签: c xcode malloc dynamic-memory-allocation


【解决方案1】:

没有办法预测内存分配失败。唯一的方法是检查malloc() 的返回值是否为空指针。

看来您的问题实际上是关于内核完成的内存overcommit。使用它内核永远不会返回空指针。默认是总是过度使用。所以要在类似 Linux 的系统上禁用它:

echo 2 > /proc/sys/vm/overcommit_memory

或者你也可以使用sysctl

sysctl vm.overcommit_memory=2

两者是等价的。

2 的值是为了确保malloc 在请求的内存超出可用物理内存(加上交换空间)的情况下返回空指针。

【讨论】:

  • 如果你使用的内核关心 /proc 并接受这些选项等,当然不受标签范围的约束,(C,XCode)......跨度>
  • @GradyPlayer 即使是 dont-like-proc-BSD 也允许通过 sysctl 进行某些更改。标签旨在成为相关性的指南。如果所问的内容很清楚实际标签是否正确,那么我在回答它时看不到任何问题。如果 OP 澄清这是不是的情况,那么我很乐意删除我的答案。
  • 你关于过度使用的观点是完全正确的,它构成了问题......我只是指出你的补救措施是针对一种系统类型的
  • @Blue Moon:那么,应该在 C 程序中编写什么代码来禁用内存过度使用?
  • @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)
【解决方案2】:

malloc() 总是返回非空指针

这并不完全正确。

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

引用手册页,(强调我的)

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


注意; [跟随cmets]

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

【讨论】:

  • 他正在寻找一种方法来预测失败,因为在某些系统上,malloc() 将成功,无论是否有足够的可用内存(这样的系统可能不会真正获取内存,直到您 访问 它,如果没有足够的,你会得到一个错误)。
  • 在某些系统上malloc 可能会返回一些虚拟的东西,然后访问失败。让我挖掘一下相关讨论......
  • @Dmitri 我不认为是这种情况here,请注意语句“malloc() 始终返回非空指针”
  • 除非必要,否则您应该引用standard,而不是 Linux 联机帮助页。注意“xcode”标签。
  • @Olaf 我明白先生,但这是一个微不足道的案例,大多数时候,手册页就足够了。
【解决方案3】:

扩展 BlueMoon 的答案,以下是 man page for malloc 关于过度使用的说法:

错误

默认情况下,Linux 遵循乐观的内存分配 战略。这意味着当 malloc() 返回非 NULL 时 不能保证内存真的可用。这是一个 非常糟糕的错误。以防万一系统出现故障 内存,一个或多个进程将被臭名昭著的OOM杀死 杀手。如果在 Linux 的情况下使用 突然失去一些随机挑选的东西是不太可取的 进程,而且内核版本足够 最近,人们可以使用 命令之类的 # echo 2 > /proc/sys/vm/overcommit_memory
另见内核文档目录,文件vm/overcommit-accountingsysctl/vm.txt

【讨论】:

  • OP 添加了标签“XCode”,所以我认为这适用于 OS-X,而不是 Linux。 (尽管我怀疑这种行为是相似的)
【解决方案4】:

经过多次测试,这似乎是 Xcode 调试问题。 结果取决于是否使用断点以及它们在代码中的位置。

一般来说,如果要删除所有断点,那么代码会正常运行,不会出现任何问题。但是如果插入了一些断点(我不清楚它们在代码中位置的影响),那么 Xcode 就会变得不稳定并在内存分配函数后崩溃。

【讨论】:

  • “我已经找到了解决这个问题的程序化解决方案”——这看起来一点也不像重新打开这个问题的令人兴奋的程序化解决方案。令人失望....
猜你喜欢
  • 2011-09-13
  • 2014-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 2016-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多