#delphi #memory-leaks #tdataset
#delphi #утечки памяти #tdataset
Вопрос:
D2010, Win7 64bit. Здравствуйте,
У меня есть событие ButtonClick с необходимостью обработки TDataSet, открытого в другой процедуре… GetDBGenericData.
Функция GetDBGenericData возвращает TDataSet. Эта процедура в основном принимает компонент TQuery, устанавливает его свойство SQL и открывает его. Затем он возвращает TDataSet на мой buttonclick.
procedure TForm1.Button2Click(Sender: TObject);
var
DS : TDataSet;
begin
DS := TDataSet.Create(nil);
DS := GetDBGenericData(dbSOURCE, 'LIST_ALL_SCHEMAS', [] );
while Not DS.EOF do
begin
ShowMessage(DS.FieldByName('USERNAME').AsString);
DS.Next;
end;
DS.Close;
DS.Free;
Моя проблема — понимание DS.
Я создаю его здесь в этой процедуре. Я «присваиваю» его набору TDataSet, который указывает на компонент. Если я НЕ освобождаю его, у меня утечка памяти (как сообщает EurekaLog).
Если я все-таки освобожу его, я получу AV при следующем запуске этой процедуры. (в частности, внутри процедуры GetDBGenericData).
Я думаю, что происходит то, что DS присваивается (в отличие от копирования) возвращаемому набору TDataSet, поэтому, по сути, я ОСВОБОЖДАЮ ОБА DS в этой процедуре и TQuery в GetDBGenericData, когда я делаю free .
Как мне «разорвать» связь, а затем удалить память, связанную ТОЛЬКО с той, которую я создаю динамически.
Спасибо, GS
Ответ №1:
Если вашей DS
переменной присваивается другая TDataSet
by GetDBGenericData
, вы Create
не должны ни Free
того, ни другого. Вы просто используете его для ссылки на существующий набор данных.
procedure TForm1.Button2Click(Sender: TObject);
var
DS : TDataSet;
UserNameField: TField; // Minor change for efficiency
begin
DS := GetDBGenericData(dbSOURCE, 'LIST_ALL_SCHEMAS', [] );
// Call FieldByName only once; no need to create or
// free this either.
UserNameField := DS.FieldByName('USERNAME');
while not DS.Eof do
begin
ShowMessage(UserNameField.AsString);
DS.Next;
end;
// I'd probably remove the `Close` unless the function call
// above specifically opened it before returning it.
DS.Close;
end;