Dies ist ein weiterer Beitrag über mich, der eine Intraweb-App mit einer 2MB-Textdatei von Speicherlecks erbt, wie von FastMM4 gemeldet, wo ich es auf 115 Instanzen einer Klasse mit jeweils 52 Byte reduziert habe.Freigeben von mehrfach referenzierten Objekten
Die Lecks sind von einer ziemlich verworrenen Instanziierung und Handhabung der Klasse. Jede Instanziierung der Klasse wird benötigt, damit die App jetzt funktioniert. Also suche ich nach Möglichkeiten, die Klasse entweder mit einer einfachen Säuberung des Klons zu klonen oder auf andere Weise zu referenzieren, oder ..?
Die erste Instanziierung der Klasse (TCwcBasicAdapter) ist als eine lokale Variable, die mit dem TObjectList (FCDSAdapters) zu einem TObjectList (nicht besitzend) und zerstörten hinzugefügt werden:
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;
Die zweite Instanziierung der Klasse auch als eine lokale Variable ist, die mit dem TObjectList (FAdapters) zu einem TObjectList (nicht besitzend) und zerstörten hinzugefügt werden:
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;
die dritte Instanziierung der Klasse, die als Teil eines Beobachter Muster ist von der TempMulticast.AddObserver (Adapter) Linie abov e. Der Betrachter wird zu TObjectList FObservers (Owning):
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;
Die TCwcBasicAdapter hier durchgesickert ist, nicht gereinigt, wenn FObservers zerstört wird.
Die letzte Sache, die ich ausprobiert habe, ändert FObservers nicht zu besitzen, Erstellen eines privaten Feldes für den Adapter, die Freigabe des privaten Feldes in TCwcCDSAdapterObserver.Destroy, aber das verursacht Fehler.
Danke,
Paul Reis
Wie werden all diese Objekte freigegeben werden, wenn die Liste sie in sind zerstört wird, wenn die Liste sie nicht besitzen? –
FreeAndNil wird in den privaten TObjectLists FCDSAdapters und FAdapters in den Destruktoren ihrer Klasse aufgerufen. Ich habe etwas Code eingefügt, um auf jedem TCwcBasicAdapter vor dem FreeAndNil iterativ Remove aufzurufen, und es hat keinen Unterschied gemacht, beide Wege machen TList.Delete. – user122603