Сброс мусора

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Сброс мусора

Сообщение Osmiy » 12.09.2016 00:07:18

Описываю ситуацию:
Разрабатываю программу, которая умеет загружать большие высокоструктурированные файлы. Т.е. при их загрузки происходит интенсивная работа с динамической памятью, часть которой после загрузки высвобождается. Загрузка происходит в потоке. Кол-во одновременно работающих потоков программа автоматически приравнивает к кол-ву процессоров. В моем случае параллельно работают до двух потоков. При загрузке тестового набора файлов программа занимает в ОЗУ гигабайт, а должна около 400 мегабайт. При закрытии файлов в программе память не освобождается ни грамма. Но если открыть заново какой-либо файл, то весь этот гиг освобождается, программа снова начинает занимать стартовые 30МБ+размер файла. И так можно проделывать много раз без накопления не освобождаемой памяти ОЗУ. Если же программу принудительно заставить запускать по одному потоку, то при загрузке этих же файлов программа занимает в ОЗУ те самые 400МБ, а при их закрытии память освобождается сразу же.
Складывается впечатление, что менеджер памяти работает с дин. памятью абсолютно по-разному в зависимости от того один или несколько потоков работают в данный момент. Если работают несколько потоков, то менеджер не то, чтобы освобождал ненужную память, он её даже не пытается повторно использовать, выделяя все новые и новые блоки. Сброс этого кучи мусора происходит, когда запускается очередной поток в одиночку (все предыдущие уже закончили свою работу).

Вопросы:
1) Может ли кто-нибуть подтвердить что менеджер именно так и работает? Или это у меня все таки косяк.
2) Пытался вызвать искусственно сброс этой кучи мусора в менеджере, создавая поток и выделяя и освобождая в нем большой кусок памяти. Не срабатывает. Может кто-нибуть знает что должно вызывать этот сброс?

ПС спрашиваю на всякий случай, может кто в курсе, на помощь не очень рассчитываю.
Osmiy
новенький
 
Сообщения: 40
Зарегистрирован: 07.05.2016 21:18:39

Re: Сброс мусора

Сообщение azsx » 12.09.2016 02:58:47

При загрузке тестового набора файлов программа занимает в ОЗУ гигабайт, а должна около 400 мегабайт. При закрытии файлов в программе память не освобождается ни грамма.

Уточните, как вы загружаете файл в озу?
Может я никогда не задумывался, у меня программы идут в 1 поток (запустил 30 штук), они читают файл, быстро обрабатывают его - пишут в бд и так 60 тысяч файлов в сутки на каждый файл. И вроде как всё освобождается нормально.
azsx
энтузиаст
 
Сообщения: 959
Зарегистрирован: 16.11.2015 06:38:32

Re: Сброс мусора

Сообщение Osmiy » 12.09.2016 04:46:29

Если кратко, то так:

Эти действия идут в главном потоке.
Пользователь через ОпенДиалог выбирает список файлов (это текстовые файлы с массивами и таблицами целых и вещественных чисел). Мой менеджер потоков создает для каждого файла по объекту, которые хранят поначалу только полный путь и имя файла. Эти объекты сохраняются в списке- это очередь на загрузку файлов.
Далее вызывается менеджер для запуска потоков. Он сравнивает число запущенных потоков с кол-вом процессоров в системе. Если это число меньше числа процессоров, и очередь на загрузку файлов не пустая, он в цикле запускает недостающее число потоков. Запуск потока происходит путем создания объекта потомка TThread в остановленном состоянии, которому передается указатель на объект из очереди, и далее этот поток запускается.

Эти действия идут в потоках.
В потоке создается СтрингЛист. В него загружается полностью текстовый файл. Он парсится. Создаются динамические структуры, объекты, массивы и прочее, в которые копируются числа после конвертации подстрок, выпиленных из файла. СтрингЛист уничтожается. Через Application.QueueAsyncCall поток сообщает приложению, что выполнил загрузку файла, и завершает свою работу.

Эти действия идут в главном потоке.
Приложение копирует указатели на созданные объекты завершённым потоком к себе в список загруженных ("открытых") файлов, уничтожает объект потомка TThtread, уничтожает и удаляет тот самый объект из списка очереди на загрузку. Тут снова вызывается менеджер для запуска потоков.


Под "закрытием" файлов подразумевается удаление по выбору пользователя тех динамических данных, полученных при загрузке файла, и удаление файла из списка "открытых" файлов.

Вот как то так.
Osmiy
новенький
 
Сообщения: 40
Зарегистрирован: 07.05.2016 21:18:39

Re: Сброс мусора

Сообщение Pavia » 12.09.2016 07:26:56

Как мерите объем памяти?
Я такими вещами не занимаюсь. Дело в том что при параллельном выделении освобождении возникает фрагментация памяти.
А сборщика мусора и дефрагментатора в паскале НЕТУ!
От сюда думайте как вам выкрутиться, вот разные варианты.
1) В вашем случае подойдет параллельный менеджер памяти. Который для каждого потока создаёт свою кучу. И по истечению времени когда поток освобождается память очищается.
2) Или просто завести массив глобальный(общий) и складывать в него ваши теги(та структура на которую вы разбираете файл).
3) Вести выделение и освобождение памяти в основном потоке. А обработку делать параллельно.
Аватара пользователя
Pavia
постоялец
 
Сообщения: 290
Зарегистрирован: 07.01.2011 12:46:51

Re: Сброс мусора

Сообщение azsx » 12.09.2016 07:30:22

СтрингЛист уничтожается.

а если попробовать сперва .clear, а уже потом .free на стринглисте?
azsx
энтузиаст
 
Сообщения: 959
Зарегистрирован: 16.11.2015 06:38:32

Re: Сброс мусора

Сообщение Osmiy » 12.09.2016 08:13:29

Pavia писал(а):Как мерите объем памяти?

Колонка Память в диспетчере задач.

Pavia писал(а):1) В вашем случае подойдет параллельный менеджер памяти. Который для каждого потока создаёт свою кучу. И по истечению времени когда поток освобождается память очищается.

Это как? Есть что об этом почитать?

Pavia писал(а):2) Или просто завести массив глобальный(общий) и складывать в него ваши теги(та структура на которую вы разбираете файл).3) Вести выделение и освобождение памяти в основном потоке. А обработку делать параллельно.

Уже не реально переделать.

azsx писал(а):а если попробовать сперва .clear, а уже потом .free на стринглисте?

В принципе это одно и тоже, но я попробовал- без изменений.
Osmiy
новенький
 
Сообщения: 40
Зарегистрирован: 07.05.2016 21:18:39

Re: Сброс мусора

Сообщение azsx » 12.09.2016 08:48:48

а если http://www.freepascal.org/docs-html/fcl ... tlist.html попробовать, он также при выходе из потомка TThread не освободится? Вкратце, так ведут себя все объекты или только некоторые?
оффтопик
хорошо, что я многопоточном программировании не разбираюсь.
azsx
энтузиаст
 
Сообщения: 959
Зарегистрирован: 16.11.2015 06:38:32

Re: Сброс мусора

Сообщение zub » 12.09.2016 10:21:45

heaptrc что говорит?
Память под что выделяется (какими кусками)?

>>Или это у меня все таки косяк.
Чаще всего так и есть))

>>Уже не реально переделать.
Если вы обрабатываете гигабайты выделяюю кучу под каждую мелочь - лучше переделать. если расход памяти не улучшится, то скорость возрастет в разы
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Сброс мусора

Сообщение Pavia » 12.09.2016 11:26:07

Osmiy
Osmiy писал(а):Колонка Память в диспетчере задач.

Это грубый метод. Менеджер памяти паскаля не спешит освобождать память так как она может понадобится. Более того виндоус тоже не спешит отвязывать страницы от процесса. Да ещё и делает резерв до 2-х раз от выделенного объема.

Если на стабильность программы это никак не влияет то можно оставить. А если завершается с нехваткой памяти то надо править программу.
Osmiy писал(а):Если кратко, то так:

Лучше выкладывайте кодом. А то так не понятно есть у вас ошибки выделения и освобождения памяти или их нету. Человеку свойственно видеть привычное и он может не замечать ошибок. За лесом - деревьев невидно!


azsx писал(а):Это как? Есть что об этом почитать?

Самое простое решение отказаться от потоков и сделать на процессах. К примеру как файнридер. Создается несколько одинаковых процессов в параметрах командой строки передаёте нужный файл. А после через общую память собираете данные в главный процесс.

Описания нет. Есть побуждения на форумах.
Про процессы можно посмотреть... Не нашёл. Если не путаю, то Emmys с исхождников делал на процессах.

С потоками можно посмотреть обсуждение здесь.
http://dxdy.ru/post1073959.html#p1073959
Вроде в OmniThreadLibrary был нужный менеджер памяти.

azsx писал(а):Уже не реально переделать.

Думаю простого решения тут нет. Я изначально делал парсер на структурах, а не на объектах. Структуры создаются за 1 проход. Деревья создаются динамически на классах. Но их можно переделать на объекты и складировать в массив объектов. В моём случае переделка не так критична так как весь код для дерева собран в одном юните.

А если говорить о мастерах-дельфи то они создают классы описывающий умные указатели и с их помощью делают динамическое управление памятью. Но это очень сложная переделка.
Аватара пользователя
Pavia
постоялец
 
Сообщения: 290
Зарегистрирован: 07.01.2011 12:46:51

Re: Сброс мусора

Сообщение Osmiy » 12.09.2016 12:04:53

Модуль heaptrc пишет всё окей- утечек нету.
СтрингЛист переписывал в свою реализацию полностью на PChar- результат тот же.

Вобщем там в потоке происходит выделение памяти:
1)СтрингЛист (под сам файл)
2)При конвертировании строки в число несколько раз выделяется строка (первый раз для копирования подстроки, второй раз при вызове Trim() ). И так до миллионов раз на файл.
3)Несколько дин. массивов от маленьких до больших (суммарно опять таки до миллионов элементов)
4)Небольшая кучка структур (размер их суммарный пренебрежимо мал)

1 и 3 являются полями класса, экземпляр которого также создается в потоке, но сам он памяти не жрет (хранит только указатели).
Что именно создает из этого "неудоляемый мусор" после считывания файла и закрытием файлов (удаление этих данных из памяти) не понятно абсолютно. Всё работает как часы без глюков и вылетов.

Добавлено спустя 4 минуты 24 секунды:
Pavia писал(а):Лучше выкладывайте кодом.

Не могу. Это уже с десяток тысяч строк код, в котором разберусь токо я :(

Добавлено спустя 3 минуты 30 секунд:
Osmiy писал(а):Всё работает как часы без глюков и вылетов.

Причем операцию открытия и закрытия всех файлов я повторял 100 раз. Ни одного байта потеряно не было, и роста потребления памяти в диспетчере тоже не наблюдалось.
Osmiy
новенький
 
Сообщения: 40
Зарегистрирован: 07.05.2016 21:18:39

Re: Сброс мусора

Сообщение zub » 12.09.2016 14:49:46

>>Модуль heaptrc пишет всё окей- утечек нету.
Ну тогда и переживать нестоит.

>>3)Несколько дин. массивов от маленьких до больших (суммарно опять таки до миллионов элементов)
Наполняются эти массивы как? массив сразу создается нужной длинны? или растет поэлементно? или растет "кэшировано" по n элементов?
zub
долгожитель
 
Сообщения: 2886
Зарегистрирован: 14.11.2005 23:51:26

Re: Сброс мусора

Сообщение Osmiy » 12.09.2016 20:38:18

Массивы выделяются разом, т.е. сразу нужного размера.

zub писал(а):>>Модуль heaptrc пишет всё окей- утечек нету.Ну тогда и переживать нестоит.

Желательно избавиться от этого. Будущая клиентура "не простит" такого.
Osmiy
новенький
 
Сообщения: 40
Зарегистрирован: 07.05.2016 21:18:39

Re: Сброс мусора

Сообщение pupsik » 12.09.2016 20:42:03

Желательно избавиться от этого.
это для отладки... Зачем в релиз пихать?
По поводу ответа на ваш вопрос:
без сорцов (тестовик, где реализован глюк, никто не отменял) вразумительный ответ не получите.
pupsik
энтузиаст
 
Сообщения: 1154
Зарегистрирован: 20.08.2014 16:20:13

Re: Сброс мусора

Сообщение and » 15.09.2016 19:16:03

Речь о Windows?
Тогда попробуйте время от времени вызывать EmptyWorkingSet. Лениво искать старые заметки по теории процесса; если вкратце - Ваша программа, как и менеджер памяти FPC, ни при чём. Виноват менеджер памяти Windows.
Импорт:
Код: Выделить всё
Function EmptyWorkingSet(hProcess:tHandle):bool; stdcall; external 'psapi.dll';
Вызов:
Код: Выделить всё
EmptyWorkingSet(GetCurrentProcess)
Аватара пользователя
and
постоялец
 
Сообщения: 124
Зарегистрирован: 16.09.2009 17:11:01
Откуда: г. Гомель, Беларусь


Вернуться в Общее

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 26

Рейтинг@Mail.ru