1

これは、FastMM4によって報告されたメモリリークの2MBのテキストファイルを持っていたIntrawebアプリを継承したことについての別の投稿です。ここでは、1つのクラスの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;  

クラスの2番目のインスタンス化も、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;  

クラスの3番目のインスタンス化は、上記のTempMulticast.AddObserver(Adapter)行のオブザーバーパターンの一部として行われます。オブザーバーがTObjectListFObservers(所有)に追加されます。

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 に答える