【问题标题】:How does std::set_new_handler make more memory available?std::set_new_handler 如何使更多内存可用?
【发布时间】:2013-09-22 15:34:02
【问题描述】:

来自std::set_new_handler

new-handler 函数是分配函数在内存分配尝试失败时调用的函数。其预期目的是以下三件事之一:

  • 提供更多可用内存
  • 终止程序(例如通过调用 std::terminate)
  • 抛出 std::bad_alloc 类型的异常或从 std::bad_alloc 派生的异常

下面的重载能保证什么吗?

void * operator new(std::size_t size) throw(std::bad_alloc){
    while(true) {
        void* pMem = malloc(size);
        if(pMem)
            return pMem;

        std::new_handler Handler = std::set_new_handler(0);
        std::set_new_handler(Handler);

        if(Handler)
            (*Handler)();
        else
            throw bad_alloc();
    }
}

【问题讨论】:

  • 您的问题是什么? “保证任何东西”是什么意思?
  • @JonathanWakely,我不应该使用“保证”这个词。我的意思是:使用这种重载方法可以通过任何方式增加成功分配的机会吗?
  • @n.m. “魔法”在什么背景下?
  • 发布的实现将调用当前的新处理程序(如果已设置),因此新处理程序可以尝试释放一些内存并抛出std::bad_alloc,调用者可以捕获它并重试new 电话。其工作方式(以及是否)完全取决于应用程序,并且仅在非常特殊的情况下才需要。在大多数应用程序中,要么不担心分配失败,要么捕获bad_alloc 并优雅地退出。
  • 对不起,我误读了这个问题。此重载或多或少是标准 operator new 的忠实实现,因此,它不保证超出标准 operator new 所保证的任何内容。

标签: c++ c++11


【解决方案1】:

std::set_new_handler 不提供内存,它设置了一个新的处理函数,以便在分配失败时使用。

用户定义的新处理函数可能能够提供更多可用内存,例如通过清除内存缓存或销毁一些不再需要的对象。默认的 new-handler 这样做,它是一个空指针,因此分配内存失败只会引发异常,因为标准库无法知道您的程序中可能不再需要哪些对象。如果您编写自己的新处理程序,则可以根据您对程序及其要求的了解,将一些内存返回给系统。

【讨论】:

  • 谢谢。是否有任何示例/参考来编写可以清除内存缓存的新处理程序?
  • 不,这取决于您的应用程序。如果您甚至没有拥有这样的缓存,那么这是不可能的。如果您有对象的全局缓存,那么让您的新处理程序删除旧元素,但细节将完全特定于您的应用程序。不过这应该很容易 - 只需让缓存中的内容过期即可。如果您需要帮助,那么您可能无论如何都不需要使用 new-handler。
【解决方案2】:

这是一个工作示例,说明自定义新处理程序的功能。

#include <iostream>
#include <new>

/// buffer to be allocated after custom new handler has been installed
char* g_pSafetyBuffer = NULL;

/// exceptional one time release of a global reserve
void my_new_handler()
{
    if (g_pSafetyBuffer) {
        delete [] g_pSafetyBuffer;
        g_pSafetyBuffer = NULL;
        std::cout << "[Free some pre-allocated memory]";
        return;
    }
    std::cout << "[No memory to free, throw bad_alloc]";
    throw std::bad_alloc();
}

/// illustrates how a custom new handler may work
int main()
{
    enum { MEM_CHUNK_SIZE = 1000*1000 }; // adjust according to your system
    std::set_new_handler(my_new_handler);
    g_pSafetyBuffer = new char[801*MEM_CHUNK_SIZE];
    try {
        while (true) {
            std::cout << "Trying another new... ";
            new char[200*MEM_CHUNK_SIZE];
            std::cout << " ...succeeded.\n";
        }
    } catch (const std::bad_alloc& e) {
        std::cout << " ...failed.\n";
    }
    return 0;
}

我不建议生产代码的演示策略,它可能过于繁重,无法预测,一次调用 new_handler 后会成功分配多少次。我在我的系统上观察到一些成功的分配(玩数字看看你的系统会发生什么)。这是一个可能的输出:

Trying another new...  ...succeeded.
Trying another new...  ...succeeded.
Trying another new...  ...succeeded.
Trying another new...  ...succeeded.
Trying another new...  ...succeeded.
Trying another new... [Free some pre-allocated memory] ...succeeded.
Trying another new...  ...succeeded.
Trying another new...  ...succeeded.
Trying another new...  ...succeeded.
Trying another new... [No memory to free, throw bad_alloc] ...failed.

Process returned 0 (0x0)   execution time : 0.046 s
Press any key to continue.

相反,从我的角度来看,释放安全缓冲区只是为了以安全的方式终止您的程序。即使是正确的异常处理也需要内存,如果没有足够的可用内存,则调用abort() (as I learned recently)。

【讨论】:

    猜你喜欢
    • 2017-01-28
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 2012-01-12
    • 2011-09-24
    • 1970-01-01
    • 2020-05-20
    • 2010-11-22
    相关资源
    最近更新 更多