释放多重引用的对象

时间:2009-06-27 15:01:54

标签: delphi memory-leaks delphi-2009 intraweb

这是关于我继承一个Intraweb应用程序的另一篇文章,该应用程序有一个2MB的内存泄漏文本文件,正如FastMM4所报告的那样,我把它归结为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;  

该类的第二个实例化也是一个局部变量,它被添加到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;  

该类的第三个实例化是上面TempMulticast.AddObserver(Adapter)行的观察者模式的一部分。观察者被添加到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;  

TCwcBasicAdapter在这里泄露,在FObservers被销毁时没有清理。

我尝试过的最新事情是将FObservers改为不拥有,为适配器创建一个私有字段,释放TCwcCDSAdapterObserver.Destroy中的私有字段,但这会导致错误。

谢谢,

保罗·赖斯

2 个答案:

答案 0 :(得分:1)

如果列表不是所有者,则在释放列表时它们不会释放对象。只是在每个项目上调用Remove也不会这样做。您必须遍历列表并在列表中的每个项目上调用Free,然后释放列表本身。

如果您创建列表所有者,那么当您释放列表时,他们会为您执行此操作。

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

答案 1 :(得分:0)

你意识到你可以自己处理物品而不让它们的主人自动处理它们?我问这个问题,因为感觉就像你试图让自动装置在所有情况下都能完成工作。