1

这是另一篇关于我继承了一个 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 中的私有字段,但这会导致错误。

谢谢,

保罗·赖斯

4

2 回答 2

1

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

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

for i := 0 to FAdapters.Count do Free(FAdapters[i]);
FreeAndNil(FAdapters);
于 2009-06-29T18:04:26.577 回答
0

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

于 2009-06-27T15:11:31.300 回答