Как избежать «обмена смертью» во время разработки? - PullRequest
8 голосов
/ 25 июля 2010

Вероятно, каждый сталкивался с этой проблемой хотя бы один раз во время разработки:

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

Как вы видите, программа начинает истощать всю системную память, ваша программа зависает, и ваша система начинает меняться как сумасшедшая. Если вы не распознаете проблему достаточно быстро и не завершите процесс, вы, вероятно, через несколько секунд перестанете отвечать на запросы, даже если указатель мыши не будет двигаться. Вы можете либо дождаться сбоя вашей программы с ошибкой «недостаточно памяти» (это может занять несколько долгих минут), либо выполнить сброс на вашем компьютере.

Если вы не можете сразу отследить ошибку, вам понадобится несколько тестов и сбросов, чтобы выяснить, что очень раздражает ...

Я ищу, возможно, кроссплатформенный способ как-то это предотвратить. Лучшим был бы код режима отладки, который выходит из программы, если он выделил слишком много памяти, но как я могу отслеживать, сколько памяти выделено? Переопределение глобальных операторов new и delete не поможет, потому что функция free, которую я вызову при удалении, не даст никакого представления о том, сколько байт освобождено.

Любые идеи приветствуются.

Ответы [ 5 ]

13 голосов
/ 25 июля 2010

Если вы работаете в системе Linux или Unix, вы можете включить setrlimit (2) , который позволяет вам настроить ограничения ресурсов для вашей программы. Вы можете делать подобные вещи из оболочки с помощью ulimit .

10 голосов
/ 25 июля 2010

Переопределение глобальных операторов new и 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);
}

Затем вы можете сделать что-то вроде:

    // 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);
    }
1 голос
/ 25 июля 2010

, потому что свободная функция, которую я вызову при удалении, не даст никакого представления о том, сколько байт освобождено

Возможно, вам просто нужно сохранить картуобъем выделенной памяти по адресу и вычтите нужное количество на основе этой информации во время свободного.

0 голосов
/ 27 июля 2010

Если вы хотите простой способ найти все эти потенциальные утечки, просто используйте ваш текстовый редактор и найдите .push_back во всем вашем исходном коде.Затем проверьте все случаи вызова этой функции и посмотрите, не находятся ли они внутри замкнутого цикла.Это может помочь вам найти некоторые плохие проблемы в коде.Конечно, вы можете получить 100 попаданий, но это можно проверить за ограниченное время.Или вы можете написать статический анализатор (используя Scitools API), чтобы найти все циклы while, у которых есть контейнерный метод с именем .push_back, который вызывается внутри них.

0 голосов
/ 25 июля 2010

Вы можете реализовать свой собственный глобальный новый оператор:

void* operator new (std::size_t size) throw (std::bad_alloc);
void* operator new (std::size_t size, const std::nothrow_t& nothrow_constant) throw();
void* operator new (std::size_t size, void* ptr) throw();

void* operator new[] (std::size_t size) throw (std::bad_alloc);
void* operator new[] (std::size_t size, const std::nothrow_t& nothrow_constant) throw();
void* operator new[] (std::size_t size, void* ptr) throw();

Затем просто установите жесткий предел того, сколько памяти вы выделяете;может быть, даже как moch Kb / sec

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...