これは、FastMM4によって報告されたメモリリークの2MBのテキストファイルを持っていたIntrawebアプリを継承したことについての別の投稿です。ここでは、1つのクラスの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;
クラスの2番目のインスタンス化も、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;
クラスの3番目のインスタンス化は、上記のTempMulticast.AddObserver(Adapter)行のオブザーバーパターンの一部として行われます。オブザーバーがTObjectListFObservers(所有)に追加されます。
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のプライベートフィールドを解放することですが、これによりエラーが発生します。
ありがとう、
ポールライス