如果第一次失败,请重新尝试内存分配

Re-attempt memory allocation should it fail the first time?

本文关键字:新尝试 内存 分配 第一次 失败 如果      更新时间:2023-10-16

我想编写一些对内存不足有抵抗力的代码。 我试图如何去做,如果任何内存分配失败,它将在此时暂停执行,并询问操作员是否可以在重新尝试分配之前尝试释放一些内存(或者如果证明不可能,他们可以选择自己终止程序,这取决于他们)

到目前为止,我的代码似乎很丑陋。 这是进行任何可能扩展数组的 std::vector 操作的块:

while(pointVector.size() == pointVector.capacity){
    // will not break past this if the while statement remains true
    // ERROR.report() has the power to kill the program if it needs to
    try{
        pointVector.reserve(pointVector.capacity * 2); // edited
    }catch(...){
        ERROR.report(Error::Severity::Memory
                    , __LINE__, __FILE__
                    , "Failed to allocate enough points"
                    , pointVector.size(), 0, 0);
    }
}
pointVector.push_back(point);

ERROR对象被专门预先分配了它的所有资源,因此它可以询问操作员而不会引起任何新问题(理论上)。 我的问题是,有没有更好的形式可以采取? 对于这种情况,C++有"重新尝试"的逻辑吗? 或者这几乎是它应该去的样子?

一般来说,不,C++没有内置的方法解决这个问题。内存不足通常不是编程语言通常可以容纳的,因此假设没有所需的内存就无法继续运行,它将失败。由于没有内在的"重试"逻辑,你留下的东西就像你所拥有的一样。抱歉,这里没有特别干净的方法。

根据"你只为你使用的东西付费"的原则,C++不会自己"重复"或"再试一次"。

在这种情况下是否真的值得再试一次,这当然是另一回事......除非您的系统正在运行系统关键型内容,并且内存不足操作是您需要处理的情况的重要组成部分,否则我会说再次尝试可能比救助更糟糕。

您还可以检查错误是否不是std::bad_alloc[或任何"您无法分配"的名称],因为如果有其他错误,则重试可能毫无意义。

您绝对应该为重复循环的次数设置限制(以防万一ERROR.report()中存在错误)。

[只要您的项目列表相当小,一次增长 32 个就可以了 - 但我看到的代码几乎与此相同会导致问题,因为一次"仅"增加 32 个到总大小为 32MB,它会导致数据被复制无数次,使应用程序看起来像挂起了, 从而从用户那里得到了错误报告。将其更改为几何增长(每次翻倍)修复了该特定错误]。

除非你有真正特殊的要求,否则如果不满足内存需求,应用程序简单地退出并不是没有道理的:让用户释放内存并再次运行程序。这避免了编写在 99.9% 的情况下不需要的额外代码,在这种情况下,这可能会极大地影响您的性能。

例如,通常push_back在摊销的恒定时间内运行,但由于容器的大小线性增加,您的"增长 + 推回"组合实际上会线性运行。这种巨大的性能下降将影响所有用户,同时仅为内存不足的一小部分提供好处。

您要查找的函数是std::set_new_handler(new_handler new_p)

它允许您指定在分配由于程序内存不足而即将失败时调用的方法。然后,此方法有机会释放一些内存,以便分配可以成功。如果该方法能够释放一些内存,则应返回 true,否则它必须引发bad_alloc异常或终止程序。(set_new_handler的文档包含更具体的信息。

使用 set_new_handler 的一个很好的功能是,您不必将每个对 new 的调用包装在 try/catch 块中,以确保您没有耗尽内存。

我认为您最好的方法是在内存池中分配内存并从那里使用内存,这样您就可以完全控制内存,并且可以进行一些清理,例如碎片整理,如果您内存不足。恕我直言,按照您建议的方式进行恢复只会延迟不可避免的事情。