![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Утечка памяти в 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. Перед разрушением соединения его надо разорвать.