【问题标题】:malloc error handlingmalloc 错误处理
【发布时间】:2012-06-19 17:31:50
【问题描述】:

除了out of memory 之外,使用malloc 分配内存时可能会出现哪些错误?处理这些错误的最佳策略是什么?

对于out of memory exception,即使内存分配失败,是否需要释放指针?

【问题讨论】:

  • 现实生活比这更糟糕:在标准 Linux 上,您的 malloc 调用可以成功,但内存实际上不可用并且您的进程被杀死。操作系统默认oversubscribe内存。这通常不是什么大问题。
  • 谢天谢地,任何希望自己的 Linux 系统性能优于 Win95 的人都可以轻松修复此默认设置... (echo "2" > /proc/sys/vm/overcommit_memory)

标签: c memory memory-management memory-leaks malloc


【解决方案1】:

在 C 中没有例外(无论如何你都不能在语言中使用),所以malloc 发出失败信号的唯一方法是返回一个空指针。所以你必须检查返回值。如果为 0,则分配失败(无论出于何种原因)并且没有分配内存 - 没有可释放的内存;否则请求数量(*)的分配成功,您将不得不在不再需要时释放内存。

(*) 小心溢出:malloc 采用size_t 参数,这很可能是一个无符号数。如果您请求带有无符号sizesize * sizeof(int) 字节并且乘法溢出(可能在获取size 的值时出错),则结果是一个小数。 malloc() 将为您分配这少量的字节以返回非空值,并根据size 的实际(大)值对返回的数组进行索引,这可能导致 分段错误 或等价的

【讨论】:

  • 你能说得更具体些吗
  • @Aman Attila 可能是指超出分配缓冲区末尾的写入,这可能会覆盖 malloc 的控制信息,导致分配失败或在任意未来 malloc 或 free 上崩溃。好吧,我猜不是……但是更新中描述的实际数字溢出比由于其他原因覆盖缓冲区要少得多,例如忘记将数组中的对象数量乘以它们的大小,或者使用 sizeof(*foo ) 而不是 sizeof(foo) 分配 foo 数组时
【解决方案2】:

我知道这看起来像是一个产品插件,但您可以在我们在CheckPointer 上的文章中了解各种内存分配错误,这是我们用于查找内存管理错误(包括此类分配错误)的工具。

【讨论】:

    【解决方案3】:

    内存不足是唯一可检测到的错误...其他错误(例如释放已释放的内存)可能导致崩溃。

    在 C 中检查内存不足的一种策略是使用 malloc 和 realloc 的包装器(您可能称它们为 xmalloc 和 xrealloc)来检查内存不足,如果是,则采取错误操作...打印一条消息并退出,或者可能尝试释放内存池,然后重试分配。这将所有测试放在一个地方,产生一致的失败消息,并保证检查所有分配尝试是否失败。下面的 cmets 讨论了可能的缺点。

    从历史上看,这种策略在 C 代码中很少见(与用这种古老语言编写的代码中普遍存在的低质量一致),但现在一些成熟的库框架包含了这种东西(尽管实现还有一些不足之处;再次强调) ,见下面的 cmets)。另一种非常可取的方法是放弃 C 并转向更现代的语言……可能是 C++,其中new 的任何失败都会导致bad_alloc 异常。

    至于你的问题......如果 malloc 失败,它返回 NULL;没有指向免费的指针。 (free(NULL) 是无操作的)。如果 realloc 失败,则原始分配保持不变。您可以通过阅读手册页或规范来找到这些内容,例如http://pubs.opengroup.org/onlinepubs/7908799/xsh/realloc.html

    【讨论】:

    • -1 包装 malloc 是一种极其有害但普遍存在的编程实践,需要废除。没有办法绕过它——你必须处理malloc 的失败,并且没有“更简单”的方法来处理它可以用包装器实现。仅中止程序的包装器可以轻松编写不检查malloc 故障的损坏的代码(因为它可以假设您的包装器永远不会返回故障)并且几乎不可能修复/追溯- 使这个损坏的代码可以在健壮的软件中使用。 GMP 和 glib 等主要库都存在这个问题。
    • 这是一个荒谬的固执的咆哮,严重夸大了情况,并且与您在stackoverflow.com/questions/3184172/… 的回答相矛盾...对最佳实践有不同意见是一回事,但您的 -1 是不需要。
    • P.S.包装器可以做的一件事是发出信号。如果那是“极其有害的”,那么 C++ 也会引发 bad_alloc 异常,而不是从“new”返回 NULL。当然,它并不是“极度有害”。
    • P.P.S.包含 p = malloc(...); 的代码如果(!p)oom();与包含 p = xmalloc(...) 的代码相比,修复/改造来做一些不同的事情并不容易,所以 no 在你的咆哮中声明是正确的,除了关于 GMP 的投诉可能例外和 glib,但是可以更改这些库以捕获和传播 longjmp(我的意思是“信号”而不是“信号”),从而使它们自己处于干净状态。使用内存故障时的异常来编写健壮的软件是可能的,即使有些人缺乏如何做到这一点的知识或想象力。
    • 无论如何,如果你编辑你的答案让我删除 -1,我会的。我欠你的只是为了找到我对另一个问题同样糟糕的答案......
    猜你喜欢
    • 2022-01-11
    • 2014-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-04
    • 2011-11-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多