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
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? –
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