Это еще один пост о том, что я унаследовал приложение Intraweb с текстовым файлом утечек памяти объемом 2 МБ, как сообщает FastMM4, где я получил до 115 экземпляров одного класса с утечкой 52 байта каждый.
Утечки связаны с довольно запутанной реализацией и обработкой класса. Каждое создание экземпляра класса необходимо, чтобы приложение работало прямо сейчас. Поэтому я ищу способы клонировать класс с помощью простой очистки клона, или ссылаться по-другому, или ..?
Первый экземпляр класса (TCwcBasicAdapter) представляет собой локальную переменную, которая добавляется в TObjectList (не Owning) и уничтожается с помощью TObjectList (FCDSAdapters):
procedure TCwcDeclaration.AttachAdapter(DS: TDataSource; const FormName, KeyFN, TitleFN: string; const Multiple: boolean = False;
const AllowAttachment: boolean = False; const AllowComment: boolean = False);
var
Forms : TCwcSessionForms;
Adapter: TCwcCDSAdapter;
KeyField, TitleField: TField;
begin
Forms := GetForms(FormName);
KeyField := DS.DataSet.FindField(KeyFN);
TitleField := DS.DataSet.FindField(TitleFN);
Adapter := TCwcBasicAdapter.Create(DS, KeyField, TitleField, Multiple);
Adapter.AttachDBPersist(Self.DBPersist);
Forms.AttachDataAdapter(Adapter);
Forms.SetAllowAttachments(AllowAttachment);
Forms.SetAllowComments(AllowComment);
end;
procedure TCwcSessionForms.AttachDataAdapter(aCDSAdapter: TCwcCDSAdapter);
var
Index: integer;
begin
if (FCDSAdapters.IndexOf(aCDSAdapter) -1)
then raise Exception.CreateFmt('Duplicate Adapter attempting to be attached on %0:s', [FFormClassName]);
Index := FCDSAdapters.Add(aCDSAdapter);
if (FDefaultAdapterIndex = -1)
then FDefaultAdapterIndex := Index;
end;
Второй экземпляр класса также является локальной переменной, которая добавляется в TObjectList (не Owning) и уничтожается с помощью TObjectList (FAdapters):
procedure TCwcCDSMulticastList.InitializeAdapters(const aSessionForms: TCwcSessionForms);
var
i, Count: integer;
Adapter: TCwcCDSAdapter;
TempMulticast: TCwcCDSEventMulticast;
begin
Count := aSessionForms.GetDataAdapterCount;
for i := 0 to Pred(Count) do begin
Adapter := aSessionForms.GetDataAdapter(i);
TempMulticast := FindDataSource(Adapter.DataSource);
if (TempMulticast = nil) then begin
TempMulticast := TCwcCDSEventMulticast.Create(Adapter.DataSource);
try
FMulticastList.Add(TempMulticast);
except
FreeAndNil(TempMulticast);
raise;
end;
end;
TempMulticast.AddObserver(Adapter);
FAdapters.Add(Adapter);
end;
end;
Третий экземпляр класса является частью шаблона наблюдателя из строки TempMulticast.AddObserver (Adapter) выше. Наблюдатель добавлен в TObjectList FObservers (Владение):
procedure TCwcCDSEventMulticast.AddObserver(const aCDSAdapter: TCwcCDSAdapter);
begin
FObservers.Add(TCwcCDSAdapterObserver.Create(aCDSAdapter));
end;
constructor TCwcCDSAdapterObserver.Create(const aCDSAdapter: TCwcCDSAdapter);
begin
inherited Create;
FOnStateChange := aCDSAdapter.OnStateChangeIntercept;
FOnAfterDelete := aCDSAdapter.AfterDeleteIntercept;
FInvalidateCursors := aCDSAdapter.InvalidateCursors;
end;
Здесь пропущен TCwcBasicAdapter, который не очищается при уничтожении FObservers.
Последнее, что я попробовал, - это изменить FObservers на «Не принадлежащий», создать приватное поле для адаптера, освободить приватное поле в TCwcCDSAdapterObserver.Destroy, но это приведет к ошибкам.
Спасибо
Пол Райс