Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Утечка памяти в TADODataset. [D7, MSSQL]


b@mboZe ©   (2004-11-26 12:07:00) 

Всем доброго времени суток.
У меня следующая задача: импортировать данные из excel файлов по списку (в списке >30 файлов) в MS SQL БД.
Возникла проблема: при занесении значений в TADODataset память, выделенная под них, не освобождается. Т.е. код типа
ADODataset.FieldValues['Field1'] := 'String constant';
дает утечку памяти. Мне, конечно, не жалко одну строку, но проблема в том, таких строк в одном .xls от 3000-7000 умножить на количество файлов = весьма ощутимая утечка памяти.
Факт утечки проверял MemProof-ом. На нижеследующий пример Memproof в результатах (Resource Details) пишет
...
    1265  SysString             0017BDFC         16  SysAllocStringLen(Liking string #5,16)
    1271  SysString             0017BDFC         16  SysAllocStringLen(Liking string #6,16)
...
    7193  SysString             0017BDFC         18  SysAllocStringLen(Liking string #993,18)
    7199  SysString             0017BDFC         18  SysAllocStringLen(Liking string #994,18)
...
т.е. не была освобождена память на строки 'Liking string #' c 1 по 1000. На закладке счетчиков ресурсов (Resource counters) он пишет:
Resources  Resource Count  Resource Size
Area Item  Current # Peak # Current Size Peak Size
...
COM CoInitialize 0  1 0   0
OLE SysString 1002   1008  17918   18395
GDI  Pen  0   1  0   0
...

Т.е. не освобождено 1002 строк, причем из OLE. Вопрос, по сути, относится скорее к COM ветке форума, однако, ИМХО, веротность найти ответ в этой ветке больше.
Может, кто-нибудь сталкивался с такой проблемой?

Вот пример кода, вызывающего утечку:
procedure TForm1.Button1Click(Sender: TObject);
var
 i: integer;
 Conn: TADOConnection;
 Comm: TADOCommand;
 ds: TADODataSet;
begin
 Conn := TADOConnection.Create(self);
 Conn.ConnectionString := 'Provider=SQLOLEDB.1;Password=;Persist'
   + ' Security Info=true;User ID=bamboze;Initial Catalog=DebitCredit;Data '
   + 'Source=PHYSALIS\BAMMSSQL;'
   + 'Workstation ID=PHYSALIS;';
 Conn.LoginPrompt := true;
 conn.Connected := true;

 Comm := TADOCommand.Create(self);
 Comm.Connection := Conn;
 Comm.CommandText := 'if object_id(''T_TMP_TEST'') is not null drop table T_TMP_TEST create table T_TMP_TEST(id integer identity(1,1), Value varchar(255))';
 Comm.Execute;

 ds := TADODataSet.Create(self);
 ds.Connection := conn;
 ds.CommandType := cmdTable;
 ds.CommandText := 'T_TMP_TEST';
 ds.Active := false;
 ds.Active := true;
 for i :=1 to 1000 do
 begin
   ds.Append;
   ds.FieldByName('Value').Value := 'Liking string #' + IntToStr(i);
 end;
 ds.Free;
 comm.Free;
 conn.Free;
 ShowMessage('Done!');
end;


b@mboZe   (2004-11-26 15:31:00) [1]

Ранним связыванием. Вот так заканчиваю сессию с excel:
if Assigned(ExcelApp) then
   begin
     ExcelApp.Workbooks[1].Close(false, EmptyParam, EmptyParam, xlLCID);
     ExcelApp.Workbooks.Close(xlLCID);
     ExcelApp.Quit;
     //FreeAndNil(Values);
     FreeAndNil(ExcelApp);
   end;
   if Assigned(ExcelWorkSheet1) then
     FreeAndNil(ExcelWorkSheet1);

Вот так начинаю сессию:
 ExcelApp := TExcelApplication.Create(self);
 ExcelWorksheet1 := TExcelWorksheet.Create(self);
 Result := false;
 ExcelApp.ConnectKind := ckNewInstance;
 ExcelApp.Connect;

 if Assigned(ExcelApp) then begin
   ExcelApp.Visible[xlLCID] := false;
   if ExcelApp.WindowState[xlLCID] = TOLEEnum(xlMinimized) then
     ExcelApp.WindowState[xlLCID] := TOLEEnum(xlNormal);
   ExcelApp.ScreenUpdating[xlLCID] := true;
 end;

 s:=filename;
 ExcelApp.Workbooks.Open(s, EmptyParam, EmptyParam,
   EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
   EmptyParam, EmptyParam, EmptyParam, EmptyParam, false, xlLCID);

 ExcelWorksheet1.ConnectTo( ExcelApp.ActiveSheet as _Worksheet);

 Values := ExcelWorksheet1.UsedRange[xlLCID].Value;
 iPLFieldsCount := VarArrayHighBound(Values, 2);

далее Values[i,j] считываю в TADOTable или TADOCommand


Johnmen   (2004-11-26 15:18:00) [2]

А от сервера автоматизации Exel отсоединяешься ? А подсоединяешься как ? Сервер выгружаешь ?


b@mboZe   (2004-11-26 14:57:00) [3]

Три раза подряд запустил импорт, результат: около 3000 неосвообжденных строк. Т.е. ADO выделяет пямять, использует, и забывает освободить.
В самом ADO проблемы могут быть?


Johnmen   (2004-11-26 14:20:00) [4]

Вот я и имел в виду - запустить импорт-выйти, запустить импорт-выйти, ...


b@mboZe   (2004-11-26 13:54:00) [5]

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


Johnmen   (2004-11-26 13:49:00) [6]

>b@mboZe

Посмотри, будет ли утечка (нарастание количества утёкшего), если
запустить-выйти, запустить-выйти, ...


b@mboZe   (2004-11-26 13:36:00) [7]

Johnmen ©   (26.11.04 13:03) [1]
Спасибо за замечания, однако утечку это не устранило :( . OLE по-прежнему не освобождает память строк.
Кстати: пробовал использовать TADOCommand ('insert T_TMP_TEST ...') вместо TADODataset, т.е. в цикле
ADOCommand.CommandText := 'insert TPriceExcelPreImport values(''Liking string #'+ IntToStr(i)+''')';
ADOCommand.Execute;
Тоже не освобождается память! Просто на этот раз пишет, что не освобождена память, выделенная под строки 'insert TPriceExcelPreImport values('Liking string #1')' и т.п.

Мастера, неужели никто не сталкивался с подобной проблемой/задачей? Какие есть альтернативные способы импортировать из excel в MS SQL ? (кроме DTS - их можно создать только на 1 конкретный excel-файл; и последовательности сохранить xls как txt, импортировать используя bcp.exe)


Johnmen   (2004-11-26 13:03:00) [8]

1. После второй строки тела цикла - ds.Post; (или 1 раз после цикла)
2. Перед разрушением соединения его надо разорвать.


Наверх

Титульная страница Поиск, карта сайта Написать письмо