2009-06-27 8 views
1

Ceci est un autre article sur moi héritant d'une application Intraweb qui avait un fichier texte de 2 Mo de fuites de mémoire rapporté par FastMM4, où je l'ai réduit à 115 instances d'une classe de fuite de 52 octets chacune.Libérer des objets à références multiples

Les fuites proviennent d'une instanciation plutôt alambiquée et de la gestion de la classe. Chaque instanciation de la classe est nécessaire pour que l'application fonctionne immédiatement. Donc, je cherche des moyens de cloner la classe avec un nettoyage simple du clone, ou un référencement différent, ou ..?

La première instanciation de la classe (TCwcBasicAdapter) est une variable locale qui est ajoutée à un TObjectList (ne pas posséder) et détruit avec le 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; 

La seconde instanciation de la classe est également en tant que variable locale qui est ajoutée à un TObjectList (ne pas posséder) et détruit avec le 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; 

le troisième instanciation de la classe est le cadre d'un modèle d'observation de la TempMulticast.AddObserver (Adaptateur) ligne abov e. L'observateur est ajouté à TObjectList FObservers (Possédant):

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; 

Le TCwcBasicAdapter fuit ici, pas nettoyé quand FObservers est détruit.

La dernière chose que j'ai essayée est de changer FObservers pour ne pas posséder, en créant un champ privé pour l'adaptateur, libérant le champ privé dans TCwcCDSAdapterObserver.Destroy, mais cela provoque des erreurs.

Merci,

Paul riz

+0

Comment tous ces objets sont-ils libérés lorsque la liste dans laquelle ils se trouvent est détruite si la liste ne les possède pas? –

+0

FreeAndNil est appelé sur les TObjectLists privés FCDSAdapters et FAdapters dans leurs destructeurs de classe. J'ai mis du code pour appeler itérativement Remove sur chaque TCwcBasicAdapter avant le FreeAndNil, et cela n'a fait aucune différence, les deux façons de faire TList.Delete. – user122603

Répondre

0

Vous réalisez que vous pouvez disposer des objets par vous-même sans leurs propriétaires auto-Éliminez d'entre eux? Je pose cette question parce que j'ai l'impression que vous essayez de faire en sorte que les systèmes automatiques fonctionnent dans tous les cas.

1

Si les listes ne sont pas propriétaires, ils ne libéreront pas les objets lorsque la liste est libérée. Le simple fait d'appeler Supprimer sur chaque élément ne le fera pas non plus. Vous devez parcourir la liste et appeler Free sur chaque élément de la liste, puis libérer la liste elle-même.

Si vous créez les listes de propriétaires, ils le feront pour vous lorsque vous libérerez la liste.

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

Bonjour les gens. Objets à références multiples. Vous ne pouvez pas avoir toutes les listes. BTW, votre compte ci-dessus est hors limites. – user122603

+1

Oui, ça aurait dû être Count-1. Merci. Non, vous ne voulez pas que toutes les listes soient propriétaires. Seulement ceux que vous voulez libérer les objets. Chaque objet doit avoir exactement un propriétaire. Si vous créez un objet et que vous l'affectez à une variable locale, vous devez soit libérer cet objet avant que la variable ne soit hors de portée, soit le transmettre à un objet qui le libérera ultérieurement. Vous créez des objets et les transmettez à des listes dont vous n'êtes pas propriétaires. Si c'est le cas, à qui appartiennent les objets? Où sont-ils libérés? – TrespassersW

Questions connexes