Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
1

Утечка памяти?

17.07.2018, 15:13. Просмотров 624. Ответов 20

Добрый день, форумчане! Я пишу парсер для своего языка программирования и начал с парсинга математических выражений методом рекурсивного спуска. "Спуск" позволяет мне создавать глубокие связки узлов, образуя дерево (математическое). Но отвлечемся от темы. Ради интереса, я написал программу которая позволять создавать новый класс, а старый хранить в новом - и так рекурсивно. Эта модель хорошо показывает метод рекурсивного спуска: сначала создается базовый класс, а потом он наполняется себе подобными образую глубокое дерево. Взгляните:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Expression
{
public:
    virtual double eval() = 0;
};
 
class FE: public Expression
{
public:
    FE * expr = nullptr;
    FE(FE* expr1) : expr(expr1) { }
    double eval()
    {
        return 1;
    }
    ~FE()
    {
        delete expr;
    }
};
 
 
int main()
{
    FE * expr = new FE(nullptr);
    {
        for (int i = 0; i < 5000; i++)
        {
            expr = new FE(expr);
        }
    }
    delete expr;
    return 0;
}
5.000 итераций, ого! Собственно, все окей - место в куче выделяется (проверено дебаггером) и удаляется, НО! В Visual Studio все падает при этих пяти тысяч итерациях с эксепшеном о переполнии стека. Причем все это дело падает, когда я все это удаляю оператором delete. Вот еще что - после многих тестов я заметил, что если провести цикл в 1000 итераций, то увеличится объем памяти программы (занимаемой памяти), что логично, но когда же я удаляю все это "добро", то память в диагностике визуалки и диспетчере задач подлетает чуть ли не в 3 раза! Проверил в онлайн компиляторах C++ - все окей, падает только при 50 миллионах итерациях и более. Собственно, вопрос такой - как можно оптимизировать мой говно код, чтоб создать по такому принципу глубокие "узлы"? Спасибо.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
17.07.2018, 15:13
Ответы с готовыми решениями:

Утечка памяти
Привет! написал программму, и не могу разобраться где утекает память. помогите кто сможет. ...

Утечка памяти?
В Лафоре такой код: #include &lt;iostream&gt; using namespace std;...

Утечка памяти
Либо я себе мозг запудрила, либо помогите мне :) есть у меня вектор vector&lt;char*&gt; names_variable;...

утечка памяти
Может кто-то проверить есть ли здесь утечка памяти? Мне почему-то кажется что есть. В задачи нужно...

20
6816 / 5957 / 2708
Регистрация: 14.04.2014
Сообщений: 25,504
17.07.2018, 16:28 2
Рекурсивный вызов деструкторов, что ли?
0
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
17.07.2018, 16:30  [ТС] 3
Само собой: деструкторы будут вызываться рекурсивно.
0
6816 / 5957 / 2708
Регистрация: 14.04.2014
Сообщений: 25,504
17.07.2018, 16:39 4
Ну вот и переполняется. Чему тут удивляться?
0
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
17.07.2018, 16:49  [ТС] 5
Хм, кажется понимаю, в чем проблема. А возможно ли разрешить эту проблему?
0
Его Правительские Звания
26 / 32 / 10
Регистрация: 13.07.2017
Сообщений: 1,058
Записей в блоге: 2
17.07.2018, 16:57 6
Попробуйте так:
C++
1
2
3
4
5
~FE() {
    if (expr != nullptr) {
        delete expr;
    }
}
0
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
17.07.2018, 17:04  [ТС] 7
А какой смысл, если я потом рекурсивно не "дойду" до этого экземпляра и не смогу вытянуть нужную иныормацию?
0
Его Правительские Звания
26 / 32 / 10
Регистрация: 13.07.2017
Сообщений: 1,058
Записей в блоге: 2
17.07.2018, 17:17 8
До какого экземпляра вы хотите "дойти"? В первом экземпляре провреряется, равен ли второй nullptr, и вызывается метод его (второго) удаления. Во втором вызывается удаление третьего и т. д. В экземпляре n expr равно nullptr, и там уже ничего не вызывается. Правильно я пишу?
P. S. Я сам не профессионал, могу чего-то не знать.

Добавлено через 6 минут
Попробуйте для отладки так:
C++
1
2
3
4
5
6
7
8
9
    FE * expr = nullptr;
    long int n = 1;
    FE(FE* expr1) : expr(expr1), n((*expr1).n + 1) { }
    ~FE() {
        if (expr != nullptr) {
            delete expr;
        }
        std::cout << n << ";";
    }
Увидите, дошло до 1 или нет.
0
19 / 10 / 5
Регистрация: 07.06.2018
Сообщений: 62
17.07.2018, 17:27 9
Цитата Сообщение от dimas6393 Посмотреть сообщение
А какой смысл, если я потом рекурсивно не "дойду" до этого экземпляра и не смогу вытянуть нужную иныормацию?
Прежде всего нужно разобраться, что ты написал. А ты написал однонаправленный список по типу первый пришел - последний ушел или, короче говоря стек.

Предлагаемая конструкция гарантирует что рекурсия деструктора будет остановлена на последнем элементе списка, а не пойдет дальше, и не будет вызван деструктор мнимого элемента, на который якобы указывает нулевой указатель. А в программировании для Windows нулевой указатель указывает в никуда. И поэтому у вас было исключение, а не из-за переполнении памяти
0
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
17.07.2018, 17:28  [ТС] 10
Почему же мне VS пишет, что идет переполнение стека?
0
3147 / 2619 / 698
Регистрация: 25.03.2012
Сообщений: 9,437
Записей в блоге: 1
17.07.2018, 18:17 11
dimas6393, бесконечная рекурсия приводит к переполнению стека.
Вы взялись писать язык программирования и при этом не знаете как реализованы вызовы функций в существующих языках?
0
(80 / 20 || 50 / 50) = x
1322 / 1008 / 392
Регистрация: 16.08.2014
Сообщений: 4,064
Записей в блоге: 1
17.07.2018, 18:19 12
Цитата Сообщение от dimas6393 Посмотреть сообщение
Почему же мне VS пишет, что идет переполнение стека?
потому что стек не ризиновый
0
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
17.07.2018, 18:21  [ТС] 13
Скорее всего, мой пример неудачный. Пожалуй, через пару минут я пртаеду пример на Java того, что я хочу на плюсах.
0
3147 / 2619 / 698
Регистрация: 25.03.2012
Сообщений: 9,437
Записей в блоге: 1
17.07.2018, 18:39 14
dimas6393, мы понимаем, что вы хотите. Вы хотите стек, стек на основе линейного списка. А возможно даже не просто список, а что-то древовидное... не надо даже пытаться уточнять, потому что конкретная форма структуры к теме не относится. И то что там вы собираетесь конкретно хранить - тоже не относится.

То что относится к теме - так это то, что вы даже простой линейный список неверно удаляете.
Список это.
C++
1
2
3
4
5
6
7
template <class T>
class List{
   class node{
      T data;
       node* next;
   }
};
При чём важно
1) класс List и класс node это разные классы. Никакого delete на самого себя в деструкторе не должно быть при таком подходе.
2) сделать либо свой шаблонный список если уж грабли чешутся "написать список", либо использовать STL, но ради бога не смешивать логику хранения/удаления списков с логикой хранимых данных. Список понятия не должен иметь, что он хранит чё за икспрешн там ваш описывает, чё за вложенные сущности в нём. и.т.д.
3) И всё-таки добавлю, нет, даже если рки чешутся, всё равно. Зачем вы не хотите использовать std::list?
0
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
17.07.2018, 18:47  [ТС] 15
Вообще, я желаю сделать парсинг математических выражений методом рекурсивного спуска. Т.е. парсер увидит число и создаст NumberExpression. Потом из пары NumberExpresspion он соберет BinaryExpression. Потом из пары BinaryExpression создаст еще один BinaryExpression. Логика, думаю, понятна: создать абстрактное синтаксическое дерево для решения простых математических выражений.
0
2616 / 1798 / 540
Регистрация: 05.06.2014
Сообщений: 5,202
17.07.2018, 19:15 16
Цитата Сообщение от dimas6393 Посмотреть сообщение
Собственно, вопрос такой - как можно оптимизировать мой говно код, чтоб создать по такому принципу глубокие "узлы"?
Сработает только в релиз-режиме с включенными оптимизациями.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct Test
{
    Test(Test*_next):next(_next){}
    Test*next=nullptr;
    void destroy()
    {
        Test*saveNext=next;
        delete this;
        if(saveNext)
            //главный трах-тибидох - хвостовая рекурсия
            saveNext->destroy();
    }
};
 
int main()
{
    Test*test=new Test(nullptr);
    for(int i=0;i<10000000;++i)
        test=new Test(test);
    test->destroy();
    std::cout<<"Применение очень сильного колдунства прошло успешно"<<std::endl;
    return 0;
}
1
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
17.07.2018, 21:10  [ТС] 17
Хых, в самом деле интересно. После того как создаешь много объектов - память увеличивается, что естественно. Когда удаляешь - она возрастает в несколько раз! Переключаешь на релиз-режим - все окей: удаляются объекты из памяти без видимой причины на увеличение памяти в несколько раз. Интересная модель памяти в разных режимах..
0
2616 / 1798 / 540
Регистрация: 05.06.2014
Сообщений: 5,202
18.07.2018, 00:14 18
Цитата Сообщение от dimas6393 Посмотреть сообщение
Интересная модель памяти в разных режимах..
Просто стек сжирает память под рекурсию, а обратно уже не возвращает. Релиз же разворачивает хвостовую рекурсию в цикл, который потребляет стек на порядки скромнее. Хотя, я не особо понимаю как вы умудрились выбить stack overflow всего на пяти тысячах вложенных вызовов. Стеки нынче большие, там и пятьдесят тысяч вызовов должны были поместиться.
1
0 / 0 / 0
Регистрация: 13.01.2018
Сообщений: 11
18.07.2018, 00:18  [ТС] 19
Собственно, всем огромное спасибо за помощь! Будем думать
0
Jesus loves me
Эксперт С++
5065 / 3088 / 351
Регистрация: 12.12.2009
Сообщений: 7,816
Записей в блоге: 2
18.07.2018, 18:13 20
Цитата Сообщение от dimas6393 Посмотреть сообщение
Будем думать
Че тут думать, используй С style и будет тебе счастье!
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
18.07.2018, 18:13

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

утечка памяти
если запустить код char *pointer = NULL; for( int i = 0; i &lt; 10; i++ ) { pointer = new char; }...

Утечка памяти
Доброго времени суток! Столкнулся с проблемой утечки памяти! Будь у меня маленькая программка,...

Утечка памяти?!
Джесс Либерти и Дэвид Хорват &quot;Освой самостоятельно С++ за 24 часа&quot;, вырезка из листинга 15.4 (стр...

Утечка памяти
Не могу понять как избежать утечки памяти в своей программе... привожу кусок в одном из мест где на...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.