处理“内存不足”的正确方法是什么?

最近,我在Windows上制作了一个CCTV节目的video播放器程序。 由于程序必须同时解码和播放许多video流,我认为它可能会遇到malloc失败的情况,并且我在每个malloc之后添加检查。

但一般来说,在我在开源项目中阅读的这些开源程序代码中,我很少发现对malloc结果的任何检查。 所以当malloc失败时,大多数程序都会崩溃。 那不是不接受吗?

我在linux上编写服务器程序的同事会为100个客户端连接分配足够的内存。 因此,虽然他的程序可能会拒绝101客户端,但它永远不会遇到malloc的失败。 他的方法是否也适合桌面应用程序?

在Linux上, malloc()永远不会失败 – 相反,OOM杀手将被触发并开始杀死随机进程,直到系统崩溃。 由于Linux是当今最流行的UNIX衍生产品,许多开发人员已经学会了永远不检查malloc()的结果。 这可能是你的同事忽略malloc()失败的原因。

在支持失败的操作系统上,我看到了两种一般模式:

  • 编写一个自定义过程来检查malloc()的结果,并在分配失败时调用abort() 。 例如, GLib和GTK +库使用这种方法。

  • 存储“可清除”分配的全局列表,例如缓存,可在分配失败时清除。 然后,再次尝试分配,如果仍然失败,则通过标准错误报告机制(不执行动态分配)报告。

遵循标准化API

即使在Linux上,ulimit也可用于获取malloc错误返回的提示。 它只是默认为无限制。

符合公布的标准存在明确的压力。 在大多数系统上,从长远来看,甚至在Linux上, malloc(3)都会返回正确的失败指示。 桌面系统确实具有虚拟内存和请求分页,但即使这样,检查malloc(3)只能在没有内存泄漏的调试程序中运行。 如果出现任何问题,有人会想要设置ulimit并跟踪它。 突然, malloc检查是有道理的。

在没有检查null的情况下使用malloc的结果在可能在malloc可能失败的平台上开放使用的代码中是不可接受的,在这些代码上它往往会导致崩溃和不可预测的行为。 我不能预见未来,不知道我的代码将去哪里,所以我会编写代码,检查malloc返回null – 更好地死,而不是表现得不可预测!

如果malloc失败,该怎么做的策略取决于应用程序的类型以及您对所使用的库的信心。 在某些情况下,唯一安全的做法是停止整个程序。

如果您的应用程序的内存使用是可预测的,那么预先分配已知的内存量并在某些块中进行分配的想法,因此转向实际上耗尽了内存是一个很好的。 您可以将其扩展为编写自己的内存管理例程以供代码使用。

这取决于您正在处理的应用程序类型。 如果应用程序的工作分为可以允许单个任务失败的离散任务,那么可以优雅地恢复检查内存分配。

但在许多情况下,响应malloc失败的唯一合理方法是终止程序。 允许您的代码在不可避免的空取消引用上崩溃将实现这一点。 转储日志条目或解释错误的错误消息肯定会更好,但在现实世界中,我们的工作时间有限。 有时迂腐error handling的投资回报不存在。

始终检查并预先分配可在此情况下释放的缓冲区,以便警告用户保存其数据并关闭应用程序。

取决于你写的应用程序。 当然,您总是需要检查malloc()的返回值。 但是,优雅地处理OOM仅在某些情况下才有意义,例如低级关键系统服务,或者编写可能使用的库时。 因此,在许多应用程序和框架中使用在OOM上中止的malloc包装器非常常见。 这些包装器通常被命名为xmalloc()或类似的。

GLib的g_malloc()也正在中止。

如果你要处理大量内存,并希望向Linux发表声明,例如“现在我有内存区ABC,我不需要B片,按你的意愿做”,看看mmap()/ madvise()库存GNU C库中可用的函数系列。 根据您的使用模式,代码最终可能比使用malloc更简单。 此API还可用于通过缓存您将要读/写一次的文件来帮助Linux不浪费内存。

它们在GNU libc info文档中有很好的文档。