Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Вопрос утечки памяти в приложения написанных на Qt.



  • Всем доброго времени суток.
    В последнее время заметил что мое приложение написанное на Qt в процессе его использования кушает все больше и больше памяти, хотя по логике такого быть не должно. Это сразу натолкнуло на мысль что в памяти остаются "потерянные" объекты, т.е. которые не используются, но при этом их забыли удалить. Прошерстил весь исходный код, нашел пару своих ляпов и исправил их. Однако это сильно не улучшило ситуацию. Решил провести эксперимент на тему "как освобождается память при принудительном удалении динамических объектов" и получил весьма интересные результаты. Опишу все по порядку:

    Первый эксперимент.
    Набросал простенькую программу на виджетах. Добавил две кнопки, одна для создания динамического объекта, а вторая соответственно для его принудительного удаления. Для данного опыта взял обычный динамический массив типа char, который создавал с использованием оператора new. При нажатии на первую кнопку создавался динамический массив на 2048 000 000 элементов и каждому элементу присваивалось значение 0xA0. При нажатии на вторую кнопку производилось удаление данного массива с помощью оператора delete. Результаты данного опыта были такими как и ожидалось: при нажатии на первую кнопку программа кушала память и останавливалась в районе 2Гб, а при нажатии на вторую кнопку уменьшалась до исходного значения. Повторное создание и удаление данного массива не приводило к увеличению занимаемой памяти после очистки.

    Второй эксперимент.
    В втором эксперименте я использовал всю ту же программу, только вместо динамического массива использовал QByteArray. Заполнение массива значениями производилось чуть дольше (что в принципе понятно), в заполненном состоянии программа кушала тоже гдето в районе 2Гб и после очистки так же занимало исходный объем памяти (около 45 метров). В данном случае все так же состыковывалось с теорией и ожиданиями.

    Третий эксперимент.
    В этом случае я модернизировал программу, добавив на ее форму QListWidget. При нажатии на первую кнопку создавалось 2048 000 объектов типа QListWidgetItem. Они добавлялись в лист виджетов и указатели на эти объекты так же сохранялись в QVector (для того чтобы их в последствии можно было удалить принудительно через оператор delete). При нажатии на вторую кнопку производилось удаление объектов путем перебора указателей в векторе и применения к каждому оператора delete, затем очищался сам QListWidget через метод clear() и плюс к этому очищался QVector от списка указателей на QListWidgetItem. После нажатия на первую кнопку объекты создавались некоторое время и программа постепенно набирала объем занимаемой памяти, до определенного значения. В QListWidgetItem появлялись элементы, общим количеством 2048 000. При нажатии на вторую кнопку все элементы из списка исчезали, однако программа занимала все тот же объем памяти!!! При повторном заполнении и очистке, программа "кушала" (в дополнении к уже существующему объему) еще маленьких кусочек памяти, и при очистке память не освобождала.

    По логике в стандартных компонентах Qt (в частности QListWidget) существует утечка памяти. И это мягко говоря нехорошо. Возможно я в чем то не прав. Хочу услышать ваше мнение на эту тему.



  • @Homer2000 А что если сделать такой же эксперимент с компонентами QML?



  • @razorqhex Ну как бы никто не запрещает, я QML пока не пользуюсь. Меня больше виджеты волнуют, ибо считается что технология завершена и отлажена, однако в них есть утечки памяти. Но как вижу никто не в курсе данной темы и об этом не задумывался.....



  • Просьба к знатокам английского языка: Переведите пожалуйста первый пост на английский язык и киньте в англоязычную ветку, видимо роскоязычная ветка совсем мертвая.....У меня с английским не очень и если я сам переведу - то никто ничего не поймет



  • @Homer2000 А сбросьте код третьего эксперимента, само добавление и удаление, тоже охота проверить.



  • @b2soft Да, конечно, выложу на GitHub и дам ссылку. Код конечно уже претерпел ряд изменений, но если захотите - сами приведете в исходный вид. Я провел еще несколько экспериментов, вместе с ссылкой опишу их.



  • Вот ссылка на проект https://github.com/homer2000/testRamSize.git



  • Оговорюсь, все предыдущие опыты проводились в Ubuntu 18.04 64bit. Значит ситуация следующая, по совету Max Schlee провел еще опыты:

    1. В программе заменил QListWidget заменил на QListView с использованием QStringListModel. Ситуация от этого не изменилась, проблемы с использованием памяти были такие же.
    2. Переключил Ubuntu с Х11 на wayland. И опять же ситуация не изменилась.
    3. Собрал программу под Windows 10 x64 (Qt5.10.1 mingw32). Тут уже получилась ситуация другая. Утечки памяти присутствовали (после удаления данных), однако совершенно в других объемах, получились приблизительно следующие цифры: При запуске приложение кушает в памяти 13 метров, после заполнения данными - 129 метров. После очистки - 29 метров.

    Есть подозрение что такие большие утечки в Ubuntu связаны не с Qt, а с системными библиотеками. Хотя не исключено что проблемы и в реализации компонентов Qt под Linux. Если у кого то установлен другой дистрибутив на базе Linux, проведите пожалуйста данный опыт и отпихнитесь о результатах.



  • @Homer2000
    Ну вот мои результаты:

    VIRT   RES   SHR
    583M 49104 39028 - after start
    714M  176M 39464 - after "Create array"
    698M  161M 39592 - after "Clear array"
    698M  161M 39592 - after "Create object"
    682M  146M 39656 - after "Delete object"
    After "Delete model" - Segfault
    

    Проверялось на Debian Linux 9 Stable 64 bit, Qt 5.10.1

    У меня такое впечатление, что, например значение занятой памяти после "Delete object" - это на самом деле не после удаления объекта, а после срабатывания какого-то внутреннего Qt-механизма, или механизма ядра по очистке памяти, потому что я замечал, что работает эта Qt-программа, ничего пользователь не делает, и тут раз - кол-во памяти изменилось. Правда не замечаю в какую сторону.



  • @xintrea Результаты похожи на мои, делать Create object не стоило, в слоте тупо создается еще один объект. Самое интересно что это касается только визуальных классов (наследников QWidget), т.к. Тот же самый QByteArray такой утечки не дает, он очищается вполне нормально. Еще момент, как я писал выше, в винде таких проблем нет (утечки есть но в значительно меньших объемах), и вот тут основной вопрос: это проблема в системе или в реализации Qt под операционную систему.


Log in to reply