如何避免在开发过程中"交换死亡"?

Cal*_*ius 8 c++ debugging memory-leaks memory-management

可能每个人在开发过程中至少遇到过一次这个问题:

while(/*some condition here that somehow never will be false*/)
{
    ...
    yourvector.push_back(new SomeType());
    ...
}
Run Code Online (Sandbox Code Playgroud)

当您看到程序开始耗尽所有系统内存时,您的程序会挂起,并且您的系统开始像疯了一样交换.如果你不能足够快地识别问题并终止进程,你可能会在几秒钟内得到一个无响应的系统,你的鼠标指针甚至都没有移动.您可以使用"内存不足"错误(可能需要几分钟的时间)等待程序崩溃,或者在计算机上点击重置.

如果您无法立即追踪该错误,那么您将需要多次测试和重置以找出哪个非常烦人...

我正在寻找一种可能的跨平台方式来防止这种情况.最好的是调试模式代码,如果它分配了太多内存,它会退出程序,但是如何跟踪分配的内存量呢?覆盖全局new和delete操作符无济于事,因为我在delete中调用的free函数不会知道释放了多少字节.

任何想法都赞赏.

Ste*_*ker 13

如果您使用的是Linux或Unix-ish系统,则可以查看setrlimit(2),它允许您为程序配置资源限制.您可以使用ulimit从shell执行类似的操作.


GMa*_*ckG 10

覆盖全局new和delete操作符无济于事,因为我在delete中调用的free函数不会知道释放了多少字节.

但你可以做到这一点.这是一个用于重载全局内存运算符的完整框架(将其放入某个global_memory.cpp文件中):

namespace
{   
    // utility
    std::new_handler get_new_handler(void)
    {
        std::new_handler handler = std::set_new_handler(0);
        std::set_new_handler(handler);

        return handler;
    }

    // custom allocation scheme goes here!
    void* allocate(std::size_t pAmount)
    {

    }

    void deallocate(void* pMemory)
    {

    }

    // allocate with throw, properly
    void* allocate_throw(std::size_t pAmount)
    {
        void* result = allocate(pAmount);

        while (!result)
        {
            // call failure handler
            std::new_handler handler = get_new_handler();
            if (!handler)
            {
                throw std::bad_alloc();
            }

            handler();

            // try again
            result = allocate(pAmount);
        }

        return result;
    }
}

void* operator new(std::size_t pAmount) throw(std::bad_alloc)
{
    return allocate_throw(pAmount);
}

void *operator new[](std::size_t pAmount) throw(std::bad_alloc)
{
    return allocate_throw(pAmount);
}

void *operator new(std::size_t pAmount, const std::nothrow_t&) throw()
{
    return allocate(pAmount);
}

void *operator new[](std::size_t pAmount, const std::nothrow_t&) throw()
{
    return allocate(pAmount);
}

void operator delete(void* pMemory) throw()
{
    deallocate(pMemory);
}

void operator delete[](void* pMemory) throw()
{
    deallocate(pMemory);
}

void operator delete(void* pMemory, const std::nothrow_t&) throw()
{
    deallocate(pMemory);
}

void operator delete[](void* pMemory, const std::nothrow_t&) throw()
{
    deallocate(pMemory);
}
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

    // custom allocation scheme goes here!
    const std::size_t allocation_limit = 1073741824; // 1G
    std::size_t totalAllocation = 0;

    void* allocate(std::size_t pAmount)
    {
        // make sure we're within bounds
        assert(totalAllocation + pAmount < allocation_limit);

        // over allocate to store size
        void* mem = std::malloc(pAmount + sizeof(std::size_t));
        if (!mem)
            return 0;

        // track amount, return remainder
        totalAllocation += pAmount;
        *static_cast<std::size_t*>(mem) = pAmount;

        return static_cast<char*>(mem) + sizeof(std::size_t);
    }

    void deallocate(void* pMemory)
    {
        // get original block
        void* mem = static_cast<char*>(pMemory) - sizeof(std::size_t);

        // track amount
        std::size_t amount = *static_cast<std::size_t*>(mem);
        totalAllocation -= pAmount;

        // free
        std::free(mem);
    }
Run Code Online (Sandbox Code Playgroud)