处理失败的内存分配
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);
注意:您可以假设 message1
和 message2
包含一个字符串“无法为变量分配内存...”,并且足够大,可以附加额外的 gubbins。
这里是健全性检查。内存分配失败的最可能原因是操作系统没有任何备用。让我们看看错误处理代码,如果我们假设没有更多的内存备用:
fprintf
可能会失败,也可能不会失败,具体取决于内部缓冲区的状态。我不知道引擎盖下的函数是什么样的,但我会假设它的内存需求很小。
我很确定调用MessageBox
会导致额外的内存分配,因为这会导致GUI 对象出现在屏幕上。因此,这肯定会失败,因此无法达到开发人员的预期。
简而言之,我建议这可以更好地处理,但正确的路径并不是那么明显。
【问题讨论】:
抛出异常,在顶层捕获并记录?或者只是调用 exit/abort。 "内存分配失败的最可能原因是操作系统没有任何备用。"不一定,而是“如果操作系统没有按要求提供足够的可用内存”。可能是length
包含一个相当大的数字,这可能导致分配失败,但fprintf
/ GUI 仍然可以工作。
【参考方案1】:
calloc
失败并不意味着错误处理路径也会失败。
calloc
可能失败,因为请求很荒谬。例如,如果length * sizeof (double)
溢出,calloc
应该会失败。或者,即使没有溢出,该请求甚至可能首先是不合理的内存量。在这些情况下,fprintf
或 MessageBox
可能会使用大量可用内存。
如果不知道 fprintf
和 MessageBox
的实现,您无法确定它们是否需要额外的内存分配。也许系统已经为他们保留了一些内存,以便在内存不足的情况下显示错误消息。
我不会担心 fprintf
和 MessageBox
失败。如果您的系统确实没有足够的可用内存来处理fprintf
或MessageBox
,那么它可能会在很多其他方面吓坏了。面对如此极端的内存压力而终止是相当合理的。
【讨论】:
@KarolyHorvath 是的,使用会导致整数溢出的参数合法地调用calloc
肯定是荒谬的。但是有很多方法可以意外地做到这一点(例如,其中一个因素以负整数开始,其中一个因素涉及用户输入,其中一个因素只是一个未初始化的变量......)。这就是使用calloc
而不是malloc
的优势之一:因此它会失败,而不是分配小于预期的缓冲区(这可能导致缓冲区溢出)。
没有区别...两个调用都不知道请求的大小是否正确...
感谢您的回答@jamesdlin。负责任的开发人员是否可以做任何事情来检查这一点(不查看实施)或只是接受这是一种风险?如果是这样,您可以将其添加到您的答案中吗?
@KarolyHorvath 你肯定知道,如果发生整数溢出,请求的大小是无效的,calloc
失败,而不是可能允许读取/写入越界。这怎么没有区别?
@jamesdlin:我不是在谈论那个场景,而是你提到的其余部分(“但是有很多方法”)。老实说,依靠calloc
捕获潜在的溢出对我来说听起来是一种非常绝望的尝试……如果这是你的最后一道防线,你就真的有麻烦了。你应该通过大量的单元测试和清理程序来寻找这些错误......【参考方案2】:
这里最大的问题是“长度”的典型大小。如果长度通常非常高(比如说 1MB 及以上),即使分配失败,也可以假设您仍然有足够的内存用于简单的消息框。 (检查的实际目标是防止这些非常大的分配)。
如果数组通常很小,最好不要显示任何框。 (您可以做的是预先分配所有必要的资源来显示窗口。但是不确定是否可以使用消息框。
【讨论】:
【参考方案3】:解决此问题的一种方法是预先分配一些永远不会使用的内存。
当你用完内存时,你free
这个区域,所以希望你的错误处理程序有足够的内存来完成它的工作。
【讨论】:
以上是关于处理失败的内存分配的主要内容,如果未能解决你的问题,请参考以下文章