【问题标题】:How to check multiple mallocs and free them if error?如何检查多个 malloc 并在错误时释放它们?
【发布时间】:2014-11-03 09:34:38
【问题描述】:

我有一个程序,我使用大量 malloc(和其他类似函数)为不同的数据类型分配内存。正如我们所知,此功能可能会失败。如何编写简洁的代码来检查内存是否已成功分配,如果没有,则释放所有以前的 malloc(如果有)?

我想也许可以编写一个函数来释放我 malloc 的每个指针,如果它们是 != NULL。但是我需要发送很多参数。 有更好的想法吗?

谢谢。

【问题讨论】:

  • 可以查看malloc()的返回值。如果它返回 NULL 则失败。
  • 您是否有任何代码与您迄今为止尝试过的或您认为可行的代码?
  • 这里是关于 malloc 和 free 的更深入的讨论,可能对 stackoverflow.com/questions/6084218/… 有所帮助
  • 很多。这个问题太笼统了。

标签: c malloc


【解决方案1】:

这实际上是一个不平凡的 C 编码习语问题。一种答案是学习 C++ 并使用auto_pointer。

在 C 语言中,我使用以下习语取得了成功。

  1. 在声明时将所有指针设置为NULL。
  2. 仅在需要时分配内存。
  3. 如果分配失败,设置一个错误值和goto一个标签在所有指针被释放的末尾。
  4. 如果由于某种原因需要提前释放指针,请再次将其设置为 NULL。
  5. 所有正常执行都必须一直执行到最后,以便释放所有内容(无中间 return)。

它最终看起来像这样:

int err = 0;
FOO *p = NULL; 
BAR *q = NULL; 
BAZ *r = NULL;

p = malloc(...);
if (!p) {
  err = P_MALLOC_FAILURE;
  goto done;
}
....
q = malloc(...);
if (!q) {
  err = Q_MALLOC_FAILURE;
  goto done;
}
....
// Done with p.  Free it early.
free(p);
p = NULL;
....
done:
  free(p);
  free(q);
  return err;

free 的定义确保如果指针最后仍为 NULL,则不会发生任何事情。如果你不喜欢重复的代码,你可以滥用宏:

#define ALLOC_OR_FAIL(P) do { \
  P = malloc(sizeof *P); \
  if (!P) { \
    err = P ## _MALLOC_FAILURE; \
    goto done; \
  } } while (0)

【讨论】:

  • 我见过这个成语,但随后用do .. while(0) 块将其全部封闭,唯一的原因是可以避免goto 并改用break。 (但最终效果 - 可能还有生成的代码 - 是相同的。)
【解决方案2】:

就像 pzaenger 说的......

ptr = calloc/malloc/realloc(parameters);

if(ptr == NULL)
{
    printf("Well shucks...");
}

足够简单。

我一直在构建一些代码,目前我也有很多参数 7/8,其中大多数是取消引用的指针等等。

我有一些使用相同 7/8 参数的函数,未来还会有更多。所以为了清理它们,我只是要把它们塞进一个结构(c struct)中。这样,我所要做的就是传递一个参数,即结构体(或者很可能是结构体的一个 ptr)。

一开始你要做的就是为结构体分配 malloc/calloc 内存,然后为结构体内部的任何指针分配 malloc/calloc 内存。

然后你来回传递这个结构,做你需要做的任何事情。

最后,您遍历结构并释放其中的所有内存 malloc/calloc'ed。然后为结构本身释放内存(如果使用了结构的 ptr)。

【讨论】:

    【解决方案3】:

    好吧,您可以这样设计您的代码,如果出现错误,那么您的程序流程会沿着调用堆栈返回,并且您的所有函数都会在返回错误条件时释放其分配的内存。

    如果您的代码组织得不是很好,那么“整齐地”释放所有以前的 malloc 的唯一可移植方法是,如果您在执行它们时存储一个全局 malloc 表,那么您每次调用时都会保持最新状态malloc 或 free(或任何其他分配函数)。

    但是,现代操作系统会在进程退出时为您释放所有内存,实际上它们可以比您更快地执行此操作,因为它们可以一次性释放整个进程的内存分配。恕我直言,一个实际的决定是直接退出而不显式释放,除非您怀疑您的代码将在会泄漏内存的系统上运行。

    【讨论】:

    • 此外,为了“巧妙地”处理问题,您的程序将不得不处理需要该内存的函数失败的事实。我只在有 BIG malloc 的代码块中看到过(因此,内存不足的风险很大,值得付出额外的努力来控制)。否则,如果您不处理它,您的程序可能会做一些奇怪的事情。通常,优雅的“内存不足”日志和退出是最佳选择。
    • 什么?全局malloc表?不释放就退出?
    • 很抱歉,但我不敢相信有人会建议不清理他们的指针。如果有人不愿意以正确的方式跟踪和清理他们的内存,那么他们应该只使用具有自动清理功能的语言。
    • @JoeManiaci 您能解释一下在退出前立即进行多次free 调用的优势吗?有关实际用例,请参阅 this answer。
    • @Matt:哦,我不知道,一个打算连续几个月 24/7 运行的应用程序怎么样,因为你选择在必要时不释放内存,你最终会用完由于您长时间运行内存泄漏而导致内存不足。不,这不是一个现实的用例。谁关心关闭程序的效率?即使您确实在乎,他的示例也将是极为罕见的极端情况。即使您确实关心并且这种情况并不少见,优秀的设计师也会选择稍微放慢速度而不是潜在的系统崩溃。见鬼,看看那个在那个人下面发帖的人。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-08
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    • 2021-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多