Почему моя программа теряет память? (работа с деревьями в C++)

Я создаю дерево динамических объектов. Класс Node имеет вектор для хранения дочерних узлов среди других переменных класса:

std::vector<Node*> child;

Деструктор класса удаляет все динамически размещенные переменные класса, а затем удаляет дочерние узлы:

~Node() {
    //Deleting the other variables
                .
                .
                .

    //Deleting the child nodes
    for(int i = 0; i < child.size(); i++) {
        delete child[i];
    }
}

В моем классе есть метод, создающий дерево заданной высоты, в котором текущий узел является корневым узлом:

void createTree(int height) {
    if(height == 0) {
        return;
    }
    for(int i = 0; i < numberOfChildNodes; i++) {
        child.push_back(new Node());
        child[i]->createTree(height - 1);
    }
}

В этом классе есть еще один метод, в котором я создаю дерево с высотой = 3, затем удаляю все дерево и создаю другое с высотой = 4, затем удаляю все дерево и создаю дерево с высотой = 5 и так далее, пока не появится дерево. достигнут предел памяти:

void highestTreePossible() {
    int i, height = 3;
    struct sysinfo memInfo;
    while(true) {
        createTree(height);
        sysinfo (&memInfo);
        if(memInfo.freeram > limit) {
            std::cout << "Highest tree possible: height = " << height;
            break;
        }
        for(i = 0; i < child.size(); i++) {
            delete child[i];
        }
        child.clear();
        height++;
    }
    for(i = 0; i < child.size(); i++) {
        delete child[i];
    }
    child.clear();
}

Проблема в том, что когда я проверяю память после запуска метода highTreePossible(), выделяется много памяти, чего быть не должно, потому что я все удалил. Почему в моем коде происходит утечка памяти?


person MrPontes    schedule 19.05.2020    source источник
comment
когда я проверяю память после запуска метода -- Как вы делаете эту проверку?   -  person PaulMcKenzie    schedule 19.05.2020
comment
Используйте шаблон RAII (std::unique_ptr).   -  person Marek R    schedule 19.05.2020
comment
@PaulMcKenzie Я использую struct sysinfo memInfo; системная информация (&meminfo); std::cout ‹‹ Свободная память: ‹‹ memInfo.freeram;   -  person MrPontes    schedule 19.05.2020
comment
Если эта информация сообщает о памяти ОС, то ваш тест недействителен. Диспетчер кучи C++ достаточно умен, чтобы удерживать выделенную память. Лучше проверить, если вы постоянно вызываете эту функцию, скажем, 1000 раз в цикле какого-либо типа. Если вы это сделали, сообщает ли meminfo, что утечка памяти увеличивается с высокой скоростью?   -  person PaulMcKenzie    schedule 19.05.2020
comment
Диспетчер памяти C++ не обязательно возвращает память ОС, поскольку очень высока вероятность того, что программе потребуется больше, а выделение из ОС обходится дорого.   -  person molbdnilo    schedule 19.05.2020
comment
Управление памятью в современной ОС намного сложнее. Это уже не 1930 год ;)   -  person Asteroids With Wings    schedule 19.05.2020
comment
@molbdnilo Если это так, то у меня очень быстро закончится оперативная память. Мне нужен диспетчер памяти, чтобы вернуть память, чтобы у меня не кончилась оперативная память. Что я могу сделать?   -  person MrPontes    schedule 19.05.2020
comment
Используйте valgrind для проверки утечек памяти. Но даже если с помощью valgrind вы обнаружите, что утечки нет, рассмотрите возможность изменения вектора указателей Node на вектор unique_ptr<Node>. Нет причин заниматься управлением памятью самостоятельно.   -  person darcamo    schedule 19.05.2020
comment
У вас не закончится оперативная память очень быстро или вообще. Ваш компьютер умен, поверьте ему :)   -  person Asteroids With Wings    schedule 19.05.2020
comment
@MrPontes - Прежде чем сделать вывод, что у вас закончится оперативная память, проведите тест, который я предложил. Если память остается на одном уровне после первого вызова, а затем не увеличивается, когда эта функция вызывается тысячу раз, то подозрений на утечку нет.   -  person PaulMcKenzie    schedule 19.05.2020
comment
@MrPontes Менеджер вернет память, если посчитает, что это хорошая идея. Он знает, что делает, и, как правило, гораздо лучше управляет памятью, чем человек.   -  person molbdnilo    schedule 19.05.2020
comment
@PaulMcKenzie Хорошо, я попробую   -  person MrPontes    schedule 19.05.2020
comment
@PaulMcKenzie Вы правы. Этот тест возвращает память ОС, поэтому он недействителен. Но дело в том, что я провел ваш тест и несколько раз подряд запускал метод highTreePossible(). Первые 3 раза все работало нормально, но на четвертый компьютер стал настолько медленным, что я даже не мог переключать вкладки. Я почти уверен, что у меня закончилась оперативная память.   -  person MrPontes    schedule 19.05.2020
comment
Возможно, ваш код содержит ошибки и не имеет отношения к распределению памяти.   -  person PaulMcKenzie    schedule 19.05.2020


Ответы (2)


Он не протекает; вы не используете действительный тест для такого рода вещей. Современные операционные системы имеют сложное управление памятью, и вы можете наблюдать, как процесс «удерживает» больше памяти, чем, по вашему мнению, ему нужно в любой момент времени. Будьте уверены, он доступен для остальной части системы, когда это необходимо.

Если вы беспокоитесь о памяти, вам нужно наблюдать постоянное, последовательное увеличение потребления для вашего процесса в течение значительного периода времени или подключаться к фактическим распределителям, используемым самой вашей программой. Отличный способ сделать это — использовать диагностический инструмент, такой как massif, который поставляется с Valgrind (если вы используете совместимую система). Есть отличные способы визуализировать это.

person Asteroids With Wings    schedule 19.05.2020

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

e.g.  $valgrind --leak-check=full ./node_test  

Итак, чтобы ответить на вопрос "Почему в моем коде происходит утечка памяти?"

В вашем коде нет утечки памяти, поскольку я тестировал/проверил его с помощью отчета valgrind (например, "Все блоки кучи были освобождены - утечки невозможны"). Однако я, кажется, заметил некоторую проблему в строке, содержащей условие выхода if(memInfo.freeram > limit), поскольку ожидается, что значение memInfo.freeram будет уменьшаться по мере роста дерева. И что ваша цель состоит в том, чтобы поддерживать рост дерева (следовательно, memInfo.freeram также будет уменьшаться) "пока не будет достигнут предел памяти", как вы упомянули выше, или "пока memInfo.freeram не упадет ниже определенного предела" как я перефразировал.

Поэтому я ожидаю, что правильное условие выхода должно быть предположительно противоположным if(memInfo.freeram < limit).

Надеюсь это поможет.

PS. Также рекомендуется использовать интеллектуальные указатели (например, std::unique_ptr, std::shared_ptr), чтобы избежать утечек памяти.

person Jeune Prime Origines    schedule 19.05.2020
comment
Когда я писал код в этом вопросе, я случайно набрал «›» вместо «‹». Но это правильно в моем исходном коде. Спасибо что подметил это. - person MrPontes; 19.05.2020