Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум на CrossPlatform.RU _ Qt GUI _ Утечка памяти QTreeWidget. Может баг QT ?

Автор: dreamcode 8.8.2010, 19:08

Люди вот два куска кода (вставка и удаление)
после того как добавить штук 300 элементов а потом их удалить то память не освобождается ...
Мож что то не то ??? помогите плис ...!!!!!

Вставка элементов :

 dir.setCurrent(path);

    QFileIconProvider iconP;
    QStringList list = dir.entryList(QDir::Dirs | QDir::Files,QDir::Type);

    for(int i=1;i<list.size();i++)
    {
       QTreeWidgetItem* item = new QTreeWidgetItem(0);
       item->setText(0,list.at(i));
       setWindowTitle(lPath);

       if(!(lPath.endsWith("\\")))
         item->setIcon(0,iconP.icon(QFileInfo(lPath+"\\"+list.at(i))));
       else
           item->setIcon(0,iconP.icon(QFileInfo(lPath+list.at(i))));

       ui->treeWidget->addTopLevelItem(item);

       itemsCount++;
    }




И код удаления :

for(int i=0;i<itemsCount;i++)
        delete (ui->treeWidget->takeTopLevelItem(0));
     itemsCount=0;


Автор: BRE 8.8.2010, 19:19

Цитата(dreamcode @ 8.8.2010, 20:08) *
после того как добавить штук 300 элементов а потом их удалить то память не освобождается ...

А чем проверяешь, что память не освобождается?
Не в диспетчере-ли задач смотришь? ;)

Автор: dreamcode 8.8.2010, 19:23

Цитата(BRE @ 8.8.2010, 19:19) *
Не в диспетчере-ли задач смотришь?


Смотрел и в диспетчере и в прогах типа ProcessInfo
Везде один результат...


А что не так с диспетчером задач то ????

Автор: BRE 8.8.2010, 19:32

Цитата(dreamcode @ 8.8.2010, 20:23) *
Цитата(BRE @ 8.8.2010, 19:19) *
Не в диспетчере-ли задач смотришь?


Смотрел и в диспетчере и в прогах типа ProcessInfo
Везде один результат...


А что не так с диспетчером задач то ????

Он показывает не ту память, которую ты пытаешься контролировать.

Автор: dreamcode 8.8.2010, 19:34

Ну размер памяти которую прога жрет возрастает при добавлении .... А при удалении не уменьшается..
Если пару разков так прокрутить то из 5МБ памяти можно получить целых 17МБ...


Автор: BRE 8.8.2010, 19:41

Цитата(dreamcode @ 8.8.2010, 20:34) *
Ну размер памяти которую прога жрет возрастает при добавлении .... А при удалении не уменьшается..
Если пару разков так прокрутить то из 5МБ памяти можно получить целых 17МБ...

Память растет, потому что процесс запрашивает ее у ОС для своего хипа (кучи), но после освобождения памяти в хипе она не обязательно отдается системе обратно, а продолжает использоваться для аллокации внутри процесса. Поэтому, по диспетчеру и не видно ее освобождение.
В общем, диспетчер плохой инструмент для отлова утечек памяти внутри процесса.

Автор: dreamcode 8.8.2010, 20:06

Цитата(BRE @ 8.8.2010, 19:41) *
но после освобождения памяти в хипе она не обязательно отдается системе обратно, а продолжает использоваться для аллокации внутри процесса.




А что тогда делать в моем случае....???? можно ведь и до 100,200,300 МБ до работаться..... Ну ведь я же все освободил то оно мне уже не нада....


А чем тогда тестить утечки памяти ???

Автор: BRE 8.8.2010, 20:26

Цитата(dreamcode @ 8.8.2010, 21:06) *
А что тогда делать в моем случае....???? можно ведь и до 100,200,300 МБ до работаться..... Ну ведь я же все освободил то оно мне уже не нада....
А чем тогда тестить утечки памяти ???

Для linux есть хороший инструмент valgrind.
Для венды не скажу, но если ты поищешь по форуму здесь и на prog.org.ru, то найдешь ответ (помню были подобные обсуждения).

Насчет утечки, а если выполнить твой код 10, 20, 50 раз, память будет расти?

Автор: DEADHUNT 8.8.2010, 20:28

бывают баги в Qt и valgrind их показывает.

Автор: Litkevich Yuriy 8.8.2010, 23:55

Цитата(dreamcode @ 8.8.2010, 23:08) *
for(int i=0;i<itemsCount;i++)
delete (ui->treeWidget->takeTopLevelItem(0));
itemsCount=0;
после удаления элемента кол-во элементов в виджете станет на единицу меньше, а ты это не проверяешь.
вместо itemsCount надо всё время звать функцию, которая вернёт кол-во элементов в виджете

Автор: DEADHUNT 9.8.2010, 0:02

Цитата(Litkevich Yuriy @ 9.8.2010, 0:55) *
после удаления элемента кол-во элементов в виджете станет на единицу меньше, а ты это не проверяешь.
вместо itemsCount надо всё время звать функцию, которая вернёт кол-во элементов в виджете

всё правильно, т.к. удаляется самый верхний элемент. количество итераций == начальному числу top level item`ом.

Автор: Гость_dreamcode_* 9.8.2010, 0:39

Цитата(Litkevich Yuriy @ 8.8.2010, 23:55) *
после удаления элемента кол-во элементов в виджете станет на единицу меньше, а ты это не проверяешь.
вместо itemsCount надо всё время звать функцию, которая вернёт кол-во элементов в виджете



Когда я добавляю элемент тогда itemsCount++

itemsCount=количество элементов в виджете ,

И что ни кто не сталкивался с проблемой утечки в QTreeWidget ???

Автор: kuzulis 9.8.2010, 7:45

Цитата
И что ни кто не сталкивался с проблемой утечки в QTreeWidget ???


Да нет никакой утечки! Расслабтесь!

Автор: dreamcode 9.8.2010, 8:07

Цитата(kuzulis @ 9.8.2010, 7:45) *
Да нет никакой утечки! Расслабтесь!


Аргументируй тогда куда память девается !!!!

Автор: Алексей1153 9.8.2010, 8:47

а вот такой код удаления, наверное, лучше

    for(;ui->treeWidget->topLevelItemCount();)
    {
        delete ui->treeWidget->topLevelItem(0);
    }



Автор: Авварон 9.8.2010, 8:59

Цитата(dreamcode @ 9.8.2010, 9:07) *
Аргументируй тогда куда память девается !!!!

блин, еще раз - диспетчер показывает ОБЩУЮ память приложения, когда-либо выделенную осью аппликухе. Удалив айтемы, память операционке ты не вернешь (да и не нужно это). В куче будет свободная память, которая может быть использована как повторно в тривьюхе, так и в других местах. Пример - создав строку размером 500 метров ты отожрешь 500 метров ОП и диспетчер этр покажет. Удалив строку, ты освободищь память в куче и создав такую же строку еще раз, память у ОС запрашиваться не будет (в диспетчере будет те же 500мб)

Автор: Алексей1153 9.8.2010, 9:21

Можно потестировать вручную :)

//некая глобальная переменная
QList<QTreeWidgetItem*> m_ControlList;


...
{
   ...
   QTreeWidgetItem* item = new QTreeWidgetItem(0);
   m_ControlList.append(item);
}


Затем, после удаления, зайти отладчиком и попробовать доступ к каждому из элементов
    for(;ui->treeWidget->topLevelItemCount();)
    {
        delete ui->treeWidget->topLevelItem(0);
    }
    
    for(int i=0;i<m_ControlList.size();i++)
    {
        try
        {
            m_ControlList[i]->parent();
        }
        catch(...)
        {
            //память недоступна
            int iii=1;
        }
    }


в консоли приложения при попытке обращения пишут
(Internal error: pc 0x201 in read in psymtab, but not in symtab.)
(хотя исключение не летит, хм, прикольно. В студии вылетает с треском :D )

Автор: Авварон 9.8.2010, 11:27

Цитата(Алексей1153 @ 9.8.2010, 10:21) *
Можно потестировать вручную :)

//некая глобальная переменная
QList<QTreeWidgetItem*> m_ControlList;


...
{
   ...
   QTreeWidgetItem* item = new QTreeWidgetItem(0);
   m_ControlList.append(item);
}


Затем, после удаления, зайти отладчиком и попробовать доступ к каждому из элементов
    for(;ui->treeWidget->topLevelItemCount();)
    {
        delete ui->treeWidget->topLevelItem(0);
    }
    
    for(int i=0;i<m_ControlList.size();i++)
    {
        try
        {
            m_ControlList[i]->parent();
        }
        catch(...)
        {
            //память недоступна
            int iii=1;
        }
    }


в консоли приложения при попытке обращения пишут
(Internal error: pc 0x201 in read in psymtab, but not in symtab.)
(хотя исключение не летит, хм, прикольно. В студии вылетает с треском :D )


в с++ SIGSEGV не выкидывает искючений

Автор: Алексей1153 9.8.2010, 12:00

Авварон, у меня в креаторе тоже не выпало, но надпись в консоли красным цветом появилась всё же

Автор: igor_bogomolov 9.8.2010, 12:20

Цитата(Алексей1153)
у меня в креаторе тоже не выпало, но надпись в консоли красным цветом появилась всё же
Красную надпись объяснить легко
inline const T &QList<T>::operator[](int i) const
{ Q_ASSERT_X(i >= 0 && i < p.size(), "QList<T>::operator[]", "index out of range");
return reinterpret_cast<Node *>(p.at(i))->t(); }

К сожалению (а может и к счастью) ошибка сегментации, так же как и деление на ноль, не являются исключениями с++ и через try/catch ты их не отловишь.

Цитата(Алексей1153)
    for(;ui->treeWidget->topLevelItemCount();)
    {
        delete ui->treeWidget->topLevelItem(0);
    }
Тогда уж так
while (ui->treeWidget->topLevelItemCount())
    delete ui->treeWidget->topLevelItem(0);

Автор: Алексей1153 9.8.2010, 12:36

Цитата(igor_bogomolov @ 9.8.2010, 15:20) *
Красную надпись объяснить легко
"QList<T>::operator[]", "index out of range"

Ну вот нет, не совсем всё так просто... Дело в том, что размер QList в моменты удаления элементов дерева не меняется - он вообще ничего не знает об этом. Индексы все корректные, но природу надписи что-то я не понял, когда сейчас попристальнее присмотрелся - даже ещё когда элементы не удалены из дерева, надпись тоже появляется ))
(хотя, до удаления по указателю сидят, и это видно через вьюер переменных, корректные данные, а после удаления - not accessible)


Цитата(igor_bogomolov @ 9.8.2010, 15:20) *
Тогда уж так

ну а тут разницы никакой, дело привычки. Я как-то while вобще не использую :)

Автор: dreamcode 9.8.2010, 13:25

Цитата(Авварон @ 9.8.2010, 8:59) *
блин, еще раз - диспетчер показывает ОБЩУЮ память приложения, когда-либо выделенную осью аппликухе. Удалив айтемы, память операционке ты не вернешь (да и не нужно это). В куче будет свободная память, которая может быть использована как повторно в тривьюхе, так и в других местах. Пример - создав строку размером 500 метров ты отожрешь 500 метров ОП и диспетчер этр покажет. Удалив строку, ты освободищь память в куче и создав такую же строку еще раз, память у ОС запрашиваться не будет (в диспетчере будет те же 500мб)



А вот и ни фига... Когда выделил память один рас (500 метров ушло) потом очистил и опять выделяешь (и опять 500 метров ушло) в суме уже один гиг.... Но так и всю оперативу можно израсходовать !!!!


Что же тогда делать ???

Автор: Алексей1153 9.8.2010, 13:30

dreamcode, щас времени повозиться нет (на работе), но, может сам сможешь (если чё - вечером сам попробую) - произведи класс от QTreeWidgetItem

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

много элементов тут не нужно создавать

Автор: dreamcode 9.8.2010, 13:32

Цитата(Авварон @ 9.8.2010, 8:59) *
Удалив строку, ты освободищь память в куче и создав такую же строку еще раз, память у ОС запрашиваться не будет (в диспетчере будет те же 500мб)


Для теста напиши вставку в лист 1000 строк (посмотри на память в диспетчере) она возрастет

потом очисть лист (смотрим опять в диспетчер) . О ЧУДО память уменьшилась .

Как тогда такое объяснить то ???

Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)