处理失败的内存分配

Posted

技术标签:

【中文标题】处理失败的内存分配【英文标题】:Handling Failed Memory Allocation 【发布时间】:2015-05-28 09:58:14 【问题描述】:

这个问题更像是一个健全的检查,而不是“请解决我的问题”。我最近继承了一些应用程序的代码,该应用程序由许多不同技能的开发人员编写了几十年。因此,试图弄清代码实际上想要做什么本身就是一项任务。

无论如何,我一次又一次地遇到这种初始化模式,其中内存是动态分配的,然后很快就检查了结果。由于这段代码在独立库和 GUI 中,以前的开发人员使用_STANDALONE 宏来检查并相应地处理错误:

double *myArray = (double *) calloc(length, sizeof(double));
if (myArray == NULL)
 
      strcat(message1, "myArray");
#ifdef _STANDALONE
      fprintf(stderr, "%s %s\n", message1, message2);
#else
      MessageBox(Window, message1, message2, MB_ICONEXCLAMATION);
#endif
      exit(EXIT_FAILURE);

注意:您可以假设 message1message2 包含一个字符串“无法为变量分配内存...”,并且足够大,可以附加额外的 gubbins。

这里是健全性检查。内存分配失败的最可能原因是操作系统没有任何备用。让我们看看错误处理代码,如果我们假设没有更多的内存备用:

fprintf 可能会失败,也可能不会失败,具体取决于内部缓冲区的状态。我不知道引擎盖下的函数是什么样的,但我会假设它的内存需求很小。 我很确定调用MessageBox 会导致额外的内存分配,因为这会导致GUI 对象出现在屏幕上。因此,这肯定会失败,因此无法达到开发人员的预期。

简而言之,我建议这可以更好地处理,但正确的路径并不是那么明显。

【问题讨论】:

抛出异常,在顶层捕获并记录?或者只是调用 exit/abort。 "内存分配失败的最可能原因是操作系统没有任何备用。"不一定,而是“如果操作系统没有按要求提供足够的可用内存”。可能是length 包含一个相当大的数字,这可能导致分配失败,但fprintf / GUI 仍然可以工作。 【参考方案1】:

calloc 失败并不意味着错误处理路径也会失败。

calloc 可能失败,因为请求很荒谬。例如,如果length * sizeof (double) 溢出,calloc 应该会失败。或者,即使没有溢出,该请求甚至可能首先是不合理的内存量。在这些情况下,fprintfMessageBox 可能会使用大量可用内存。

如果不知道 fprintfMessageBox 的实现,您无法确定它们是否需要额外的内存分配。也许系统已经为他们保留了一些内存,以便在内存不足的情况下显示错误消息。

我不会担心 fprintfMessageBox 失败。如果您的系统确实没有足够的可用内存来处理fprintfMessageBox,那么它可能会在很多其他方面吓坏了。面对如此极端的内存压力而终止是相当合理的。

【讨论】:

@KarolyHorvath 是的,使用会导致整数溢出的参数合法地调用calloc 肯定是荒谬的。但是有很多方法可以意外地做到这一点(例如,其中一个因素以负整数开始,其中一个因素涉及用户输入,其中一个因素只是一个未初始化的变量......)。这就是使用calloc 而不是malloc 的优势之一:因此它会失败,而不是分配小于预期的缓冲区(这可能导致缓冲区溢出)。 没有区别...两个调用都不知道请求的大小是否正确... 感谢您的回答@jamesdlin。负责任的开发人员是否可以做任何事情来检查这一点(不查看实施)或只是接受这是一种风险?如果是这样,您可以将其添加到您的答案中吗? @KarolyHorvath 你肯定知道,如果发生整数溢出,请求的大小是无效的,calloc 失败,而不是可能允许读取/写入越界。这怎么没有区别? @jamesdlin:我不是在谈论那个场景,而是你提到的其余部分(“但是有很多方法”)。老实说,依靠calloc 捕获潜在的溢出对我来说听起来是一种非常绝望的尝试……如果这是你的最后一道防线,你就真的有麻烦了。你应该通过大量的单元测试和清理程序来寻找这些错误......【参考方案2】:

这里最大的问题是“长度”的典型大小。如果长度通常非常高(比如说 1MB 及以上),即使分配失败,也可以假设您仍然有足够的内存用于简单的消息框。 (检查的实际目标是防止这些非常大的分配)。

如果数组通常很小,最好不要显示任何框。 (您可以做的是预先分配所有必要的资源来显示窗口。但是不确定是否可以使用消息框。

【讨论】:

【参考方案3】:

解决此问题的一种方法是预先分配一些永远不会使用的内存。

当你用完内存时,你free这个区域,所以希望你的错误处理程序有足够的内存来完成它的工作。

【讨论】:

以上是关于处理失败的内存分配的主要内容,如果未能解决你的问题,请参考以下文章

错误:在文件 custom.f90 的第 463 行:内存分配失败

如何模拟内存分配错误

new与malloc的区别struct与class的区别

new与malloc的区别struct与class的区别

JVM并发分配内存解决方案

使用新的内存分配失败