« first day (342 days earlier)      last day (2861 days later) » 

11:12 AM
Приветствую. Кто-нибудь сталкивался с тем, что в определённых ситуациях QThreadPool не удаляет QRunnable по завершению работы последнего? Часть удаляет, часть - нет. Код одинаковый, бесконечных циклов нет, бесконечных ожиданий нет. По логам доходит до выхода из QRunnable::run(), но его деструктор не вызывается. Флаг на автоудаление стоит.
Qt 5.7
 
11:25 AM
@alexis031182 привет, посмотрите чему равно ref во время исполнения QRUnnable
это непубличный член QRunnable
 
Привет. Думаете, что вот здесь:
if (autoDelete && !--r->ref) delete r;
@ixSci ?
 
@alexis031182 не знаю, но нужно понять, чему равно ref и от этого уже плясать
 
@ixSci Это в тредпуле в исходниках.
 
я понял
я на эту функцию смотрю
 
@ixSci Понял Вас. Мне только трудно с отладчиком. Дело в том, что программа запускает код, который и выполняется многопоточно в отдельном процессе.
 
11:31 AM
@alexis031182 но ведь можно поставить точку останова в этом коде?
 
@ixSci Да запускается этот процесс отдельно через QProcess и отладчик уже не работает.
 
хех, как всё сложно
ну можно тогда запустить в текущем процессе и посмотреть в каком месте лежит ref
 
@ixSci Да, такой геморрой это оказалось
 
потом, уже в другом процессе сделать каст к int* и тупо вывести содержимое памяти
точнее к char*
т.е. в отдельном процессе мы не будем пользоваться точкой останова
есть ещё один вариант, делали у меня так знакомые в линуксе: просто добавляют деление на ноль, там где нужна точка останова
 
@ixSci Их много этих QRunnable, но выбора нет, буду пытаться пробовать как Вы сказали.
 
11:34 AM
программа падает и уже в gdb смотрите back trace
 
@ixSci Инетересный подход с делением, не догадался бы ))
@ixSci Спасибо, попробую :)
 
если их много, тогда совершенно точно нужно узнать где лежит ref, а потом уже кастить к char* и проверять во время исполнения нужные байты
если они содержат подозрительные значение, тогда либо ронять приложение, либо что-то выводить
это уже как Вам больше нравится :)
 
@ixSci Что-то мне совсем не нравятся такие вещи в Qt. Вот с QNetworkAccessManager до сих пор не пофиксили. Утечка так и осталась. Хотя таск уже давно взяли в обработку.
 
@alexis031182 а она точно есть?
было бы интересно посмотреть, но времени пока совсем нет
а вообще, код Qt мне не очень нравится. Там случаются огрехи и не очень редко
а так как код довольно убог, местами, это не добавляет оптимизма
 
@ixSci Да, я здесь когда вопрос на сайте задавал, там ссылку оставил прямо в вопросе на этот таск на багтрекере. Там сначала в обсуждениях немного неповерили, но не я один такой, кто заимел эту проблему, и вроде как взяли в работу
 
11:39 AM
@alexis031182 просто это необязательно утечка, в линуксе весьма своеобразный менеджер памяти
поэтому может создаваться впечатление, что есть утечка там, где её нет
 
@ixSci Мне многое в Qt нравится, всё что с гуи связано, а вот проблемы с сетью - есть.
 
у меня так было: писали приложение, которое съедало всю память и ОС падала
ubuntu это была
 
@ixSci Да, на то, что утечки нет, тролли упирали
 
утечки не оказалось, а вот про memory trim я узнал
@alexis031182 это есть. Поэтому я стараюсь не использовать из Qt ничего, кроме GUI
всё остальное мне не нравится
 
@ixSci Память не то чтобы утекает, она тупо не освобождается вообще. Если качать много файлов из сети, картинки например, то в итоге всё озу съедается
 
11:41 AM
@alexis031182 ну у меня была такая же ситуация
 
Причём зачищаются и запросы и сам сетевой менеджер
Как решили?
 
@alexis031182 всё верно, а у меня были умные указатели поверх AVPacket
@alexis031182 memory trim
я писал Вам про это, но Вам не помогло
возможно у Вас реальная утечка
 
Да, я помню. мегабайт 10 возвращается, а остальное остаётся занятым. На виндовсе таже ситуация
 
@alexis031182 т.е. на винде тоже память уходит?
 
Да, один к одному, тот же самый пример минимальный, который я здесь приводил
 
11:44 AM
@alexis031182 а киньте мне ссылку, я как-нибудь посмотрю
 
один момент
3
Q: Утечка памяти при использовании QNetworkAccessManager

alexis031182Заметил, что приложение стало "поедать" память. Начал отключать функционал, одну часть кода за другой. Осталась только отправка и обработка сетевых запросов к вебсерверу. Проверил через valgrind. Помимо привычных уведомлений об утечках (и их возможности) где ни попадя (как известно, фреймворк Qt ...

 
@alexis031182 спасибо, постараюсь в этом месяце глянуть
 
Вам спасибо. А то я чувствую троллей ждать придётся долго, а что ещё можно сделать, увы, не знаю.
 
 
2 hours later…
1:58 PM
@ixSci Сейчас попробовал 5.7 на виндовс в эмуляторе дропбокса. 15 Мб в среднем остаётся против 60 линуксовых. На 5.6 на сколько помню, когда пробовал, давно уже, вроде было также. Странно, может я, конечно, не прав. Но всё равно 15 МБ тоже деньги. Сейчас пробую подряд две сессии. Увеличится эти 15 или нет, посмотрим.
 
@alexis031182 так только 15-60 отжирает и не увеличивается?
 
@ixSci Он сначала 70 Мб съедает, затем, когда загрузка заканчивается, опускается до 15 Мб. Вот хочу две ссесии попробовать подряд по 5000 ссылок скачать. Посмотреть, что получится
А если ничего не качать, то программа весит около 2Мб
 
@alexis031182 но дальнейшего увеличения потребления не происходит? Просто часть памяти не возвращается?
 
Я вот и хочу проверить, чтобы не завершая процесс повторить загрузку повторно. Увеличится или нет размер этот.
А вот с QRunnable похоже - тухло. Не удаляет часть из них. Так в памяти и висят. Сделал сейчас простую проверку через shared указатели. То есть из QRunnable::run() контекст выполнения выходит у всех (этими же указателями проверил), а деструктор не вызывается у многих. В общем, придётся переделывать. Вручную удалять буду, без автоделетинга.
 
2:46 PM
@ixSci Проверил со второй сессией. Выросло с 15 до 16 МБ. То есть всего мегабайт прибавило. То есть вроде бы небольшой рост потребления есть (на 5000 картинок), но не катастрофичный. Хотя конечно если постоянно качать, то прибавка даже и в мегабайт - это много.
 
@alexis031182 а значение ref так и не проверили?
 
@ixSci Вывод тогда пока такой: QNetworkAccessManager неприемлемо использовать на закачки на длительное время. Даже если его уничтожаешь со всеми объектами QNetworkReply всё равно какие-то хвосты остаются. Разве что процесс перезапускать время от времени, но это чистой воды костыль.
 
@alexis031182 не факт, что это утечка
@alexis031182 можно пустить на какой-нибудь машине на несколько дней, чтобы постоянно что-то качало
тогда можно будет делать выводы
но я бы вообще не стал использовать сетевые средства Qt — лучше boost
 
@ixSci До ref ещё не добрался пока. Не знаю даже, мне теперь править всё равно код придётся.
У меня на линукс постоянная закачка включена, т.к. там растёт постоянно. На виндовсе длительную закачку не пробовал.
 
@alexis031182 т.е. со временем памяти уходит всё больше и больше?
 
2:54 PM
А с бустом я просто не знаком, но видимо когда-нибудь придётся, потому что такие проблемы, как сейчас, это ещё хуже.
Да, растёт постоянно.
 
дело в том, что asio использует куда больше людей, чем весь Qt, я полагаю
не говоря уже о сетевом компоненте.
значит там выявлено и исправлено больше багов
 
Да вот я в своё время неправильный выбор сделал.
 
да и там асинхронность нормальная, в отличие от довольно спорной модели QNetworkManager
 
Я попробую начать изучать. Текущее положение дел с Qt мне совсем не нравится.
@ixSci Спасибо Вам за помощь. Если будет возможность, посмотрите, пожалуйста, у себя свежим взглядом этот пример на виндовсе с сетью. Может это я на самом деле туплю. У Вас опыта и знаний невпример больше. Хотя бы просто, чтобы и вопрос закрыть здесь на сайте.
 
@alexis031182 хорошо, постараюсь
 
 
2 hours later…
4:38 PM
@ixSci До ref не добраться. У меня Qt с сайта скачен, а там отладочной информации нет. В итоге я не могу в отладчике пройтись по исходникам Qt. Это мне его тогда пересобирать надо или ставить из пакетов древнюю версию. На нуль делить тоже не могу, некуда это вставлять. По идее в деструктор надо QRunnable, но он просто не вызывается. Сегодня не мой день :)
Вообще вот это непонятно. Если деструктор не вызывается, то значит ref там не -1, а больше. Но тогда копии всё равно в пуле находятся. Объект наследника QRunnable сразу в тред отправляюю и далее он нигде не используется.
Получается, что даже повлиять на это нет никакой возможности и удалять QRunnable вручную, установив флаг autodelete в false.
 
@alexis031182 просто выведите кусок памяти, по которому располагается QRunnable объект до и после того, как поместите его в пул. То, что изменится и будет позиция куа
вообще говоря, можно и проще поступить. У созданного объекта ref будет состоять из одних FFFFFFF
поэтому получить эту позицию не проблема
ну это всё нужно только в одном случае: Вам интересно найти баг(если он есть) и исправить его в Qt. Если нет, то просто плюньте и удаляйте руками
 
5:19 PM
@ixSci На самом деле очень интересно, но это уже выше моего понимания происходящего. Сейчас в отладчике только адрес QRunnable показывает, да можно ещё редактор памяти на этот адрес открыть.
 
@alexis031182 именно, нужно смотреть память
Непойму откуда там d-pointer
там его не должно быть
первые 4 байта это vptr
потом 4 байта ref идут, все нули — так и должно быть
вот теперь надо смотреть, как вторые 4 нуля будут менятся
 
@ixSci "_d" - это моё. Я его в наследнике использую. Типа внутренний класс для данных.
 
понял
тогда непонятно что ещё за 8 байтов там
32 бита или 64?
 
64 бита
 
5:34 PM
тогда первые 8 байтов это vptr, потом 4 байта ref, и ещё 4 байта заполнителя
значит ref у нас 1
 
А как Вы смотрите? Это с выделенной позиции "С0"?
 
да
 
*"с0"
 
c0 это первый байт объекта QRunnable
они идут задом наперёд(LE, intel)
т.е. первый байт это «низший» байт
 
Ага, то есть получается, мне нужно поймать того QRunnable, который не вызовет деструктор и посмотреть его значение вот по этим позициям, я правильно понял?
 
5:38 PM
да
по одной позиции, 9 байт от начала объекта
это и буде значение ref
если я всё правильно интерпретировал
 
Понял Вас. Тогда сейчас займусь, они самые последние в очереди идут - те, которые почему-то не удаляются
 
@alexis031182 я сейчас в оффлайн, если что — завтра спишемся
 
@ixSci Спасибо Вам большое, это весьма познавательно
 
@alexis031182 не за что
 
5:58 PM
@ixSci, кажется, нашёл
"02 00 00 00" получается десятичное значение "2". Это значит, что два экземпляра в пуле сидит или ref где-то неправильно считается, и потому QRunnable не удаляется.
Я разместил точку останова на самом выходе из QRunnable::run(). Поначалу идут все с единицами, но затем начинают проскакивать с двойками, перемежаясь с единицами.
Да, всё так, единицы с двойками. Из 269 QRunnable по меньшей мере 50 штук идут с двойками. Далее уже не стал смотреть.
Я из этого процесса, из-за известного мне поведения QNetworkAccessManager, убрал вообще отправку запросов в сеть, но память тем не менее убегала. А из всего того, что активно в этом процессе создаётся и удаляется находится как раз вот в этих QRunnable. Но там в коде нет ни одного указателя, не обёрнутого в shared или scoped. Откуда были утечки, вообще не мог понять, тем более что отладка затруднена. А тут вот оно что :(
 
6:25 PM
Тролли наверное не примут скриншоты карт памяти. Надо или какой-то минимально собираемый пример придумать или ещё как-то обосновать. Это если получится воспроизвести. Хотя с другой стороны, я под отладчиком запускал в пуле QRunnable, получается, друг за другом, с паузами, пока смотрел на адреса. Это означает, что порядок не важен и скорее всего проблема повторится, если просто понапихать любых QRunnable в пул.
Попробую, в общем, в отдельном проекте.
 
 
1 hour later…
7:37 PM
Похоже, что немного опоздали, уже есть похожий таск в багтрекере. Пример, воспроизводящий проблему там, правда, на QtConcurrent, но это не важно, т.к. последний, насколько я помню, те же QRunnable использует. А вот примечателен тот момент, что как и у меня используется связка "QThreadPool::releaseThread()" и "QThreadPool::reserveThread()". Может из-за них в т.ч. проблема.
 

« first day (342 days earlier)      last day (2861 days later) »