| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Базы данных и репортинг > Многопоточность и БД |
| Автор: OVT 19.4.2010, 12:48 | ||||||
| Добрый день! Есть приложение (delphi 6, Windows XP SP3), предназначенное для синхронизации данных в двух различных БД (MS SQL 2005 через ADO и Sybase 7 через BDE). Обработка данных происходит по зацикленному сценарию, состоящему из последовательного вызова нескольких процедур. Принцип работы каждой процедуры заключается в чтении данных с помощью TQuery в динамические массивы из каждой БД, сравнении прочитанных данных и, в зависимости от результатов сравнения, добавлении, удалении или обновлении данных в этих БД. Весь сценарий обработки вынесен в отдельный поток. На главной форме приложения отображается ход (TProgressBar) и результаты (TMemo, TChart) обработки данных. Кроме того, главная форма содержит несколько параметров (TEdit, TCheckBox), используемых при обработке данных в потоке. Все "общение" между рабочим потоком и потоком приложения происходит через Syncronize, т. е. ни к каким глобальным переменным или контролам главной формы рабочий поток на напрямую не обращается. Для рабочего потока в общем TDataModule созданы TDataBase и TADOConnection для подключения к соответствующим БД, а для TDataModule еще и отдельный TSession. Вроде, все рекоммендации, изложенные в статье Петровича http://forum.vingrad.ru/topic-60076.html (огромная благодарность автору!), мною учтены, программа работает, но наблюдается постоянный рост объема используемой памяти ~ 20MB за один цикл. Таким образом, через 50 - 60 циклов программа занимает около 1.2 GB и начинаются ошибки, в основном при обращении к MS SQL, типа "истек таймаут", "неверные параметры хранимой процедуры" и т. п. Подозревая наличие утечки памяти, пытался использовать FastMM4, но отчет показал наличие всего нескольких утечек, и то, похоже, не моих, по несколько десятков байт: 13 - 20 bytes: TObjectList x 3, Unknown x 3 21 - 36 bytes: TWinHelpViewer x 1 37 - 52 bytes: THelpManager x 1 Хотя с FastMM4 работаю впервые и, скорее всего, просто не умею им пользоваться. Некоторое время назад я написал аналогичное приложение, в котором не использовал потоки и ADO. Подобных фокусов с пожиранием памяти в нем я не наблюдал. Думаю, что собака порылась либо в потоке (видимо я упустил что-то важное для работы с БД), либо это связано с ADO, или тем, как я его использую в отдельном потоке. Не подскажете, где мой косяк? Исключительно с целью представления о структуре программы, привожу выдержки из кода:
Главная форма
Поток
|
| Автор: imageman 29.4.2010, 17:13 |
| я бы (для начала) открывал доступ к БД из основного потока (например при нажатии на кнопку Старт) и не закрывал бы связь с БД на протяжении всего рабочего времени... Что-то мне подсказывает, что проблема может быть в частом отрытии-закрытии. Но у меня мало опыта. Кстати, глобальные переменные я использую вовсю. Правда, как правило, значения глобальной переменной меняется в основном потоке, а считываются в дочерних. Как я понимаю на чтение никаких проблем быть не должно. (Да и запись пройдет нормально, только логика алгоритма может быть нарушена.) |
| Автор: OVT 4.5.2010, 10:59 |
| На самом деле доступ к БД открывается один раз, когда стартует поток по нажатию на кнопку "Старт". Дальнейшая обработка крутится внутри Execute до тех пор, пока в основном потоке не будет нажата кнопка "Стоп". У меня закралось подозрение, что я не правильно настраиваю (точнее оставляю по умолчанию все свойства) TADOQuery и TADOStoredProc. При подсчете количества записей в запросе (RecordCount) здорово увеличивается объем используемой памяти, гораздо больше, чем требуется для помещения в память всего результата запроса. После подсчета числа записей я аллокирую массив под данные - память расходуется, но в сотни раз меньше. Дальше, когда я начинаю последовательно читать записи и заносить данные в массив, память опять расходуется. При закрытии запроса (Active := False) память не освобождается полностью. Складывается такое ощущение, что память, израсходованная при подсчете числа записей, не освобождается. По диспетчеру задач очень сложно определить количество памяти, занимаемое приложением в тот или иной момент времени, для детального анализа и поиска утечки памяти. Если я правильно понимаю, то не существует функции, возвращающей объем памяти, занятый конкретным приложением. По крайней мере, я пока не нашел такой. |