2009-06-27 7 views
1

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

+0

Wie werden all diese Objekte freigegeben werden, wenn die Liste sie in sind zerstört wird, wenn die Liste sie nicht besitzen? –

+0

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

Antwort

0

Sie erkennen Sie von Objekten selbst, ohne dass ihre Besitzer Auto-dispose von ihnen verfügen kann? Ich frage das, weil es sich anfühlt, als ob du versuchst, die Automaten dazu zu bringen, den Job in allen Fällen zu erledigen.

1

Wenn die Listen keine Eigentümer sind, werden sie die Objekte nicht freigeben, wenn die Liste freigegeben wird. Das Aufrufen von Remove für jedes Element wird es auch nicht tun. Sie müssten die Liste durchlaufen und Free für jedes Element in der Liste aufrufen und dann die Liste selbst freigeben.

Wenn Sie die Listenbesitzer erstellen, werden sie dies für Sie tun, wenn Sie die Liste freigeben.

for i := 0 to FAdapters.Count do Free(FAdapters[i]); 
FreeAndNil(FAdapters); 
+1

Hallo Leute. Mehrfach referenzierte Objekte. Sie können nicht alle Listen besitzen. BTW, Ihre Zählung oben ist außerhalb der Grenzen. – user122603

+1

Ja, es sollte Count-1 gewesen sein. Vielen Dank. Nein, Sie möchten nicht, dass alle Listen Eigentümer sind. Nur diejenigen, die die Objekte freigeben möchten. Jedes Objekt sollte genau einen Besitzer haben. Wenn Sie ein Objekt erstellen und es einer lokalen Variablen zuweisen, müssen Sie entweder das Objekt freigeben, bevor die Variable den Gültigkeitsbereich verlässt, oder es an ein Objekt übergeben, das es später freigibt. Sie erstellen Objekte und übergeben sie an Listen, von denen Sie sagen, dass sie keine Eigentümer sind. Wenn das der Fall ist, wer besitzt dann die Objekte? Wo werden sie befreit? – TrespassersW