4

FastMM4によって報告されたメモリリークの2MBテキストファイルを持つIntrawebアプリを継承しました。1つのクラスの115個のインスタンスが52バイトをリークしています。

悪意のある人物の簡単な説明は次のとおりです。

TCwcBasicAdapter = class(TCwcCustomAdapter)  
  protected  
    FNavTitleField: TField;  
    function GetAdapterNav(aDataSet: TDataSet): ICwcCDSAdapterNav; override;  
  public  
    constructor Create(aDataSource: TDataSource; aKeyField, aNavTitleField: TField; aMultiple: boolean);  
  end;  

インターフェースは次のとおりです。

  ICwcCDSAdapterNav = interface(IInterface)  

プロパティは参照カウントされているので、間違ったツリーを吠えていますか?インターフェイスプロパティがクラスの破棄を防ぐことができる状況はありますか?

上記のメソッドの実装は次のとおりです。

function TCwcBasicAdapter.GetAdapterNav(aDataSet: TDataSet): ICwcCDSAdapterNav;
var
  AdapterNav: TCwcCDSAdapterNavBase;
begin
  result := nil;
  if Assigned(aDataSet) then begin
    AdapterNav := TCwcCDSAdapterNavBasic.Create(aDataSet, FKeyField.Index, FNavTitleField.Index);
    try
      AdapterNav.GetInterface(ICwcCDSAdapterNav, result);
    except
      FreeAndNil(AdapterNav);
      raise;
    end;
  end;
end;

次のように宣言されたクラスを使用します。

TCwcCDSAdapterNavBase = class(TInterfacedObject, ICwcCDSAdapterNav)
4

3 に答える 3

4

FastMMは、リークされたものとそれが作成された場所を提供する必要があります。
それはそれを本当の犯人に絞り込むのに役立ちます:誰が何を漏らしているのですか?

あなたの質問が本当に何なのかわかりませんか?
コードが不完全であるか、問題のコードではありません。クラスにはInterfaceプロパティもInterface private Fieldもありません。これは、無害なInterfaceを返すメソッドだけです。

編集:ICwcCDSAdapterNavを実装しているオブジェクトのコードを見ないと、それが実際に参照カウントされているかどうかを判断できません。
TInterfacedObjectの子孫でない場合は、参照カウントされておらず、この自動的に解放されることに頼ることができない可能性があります...

このCodeRage2セッションダミーのためのメモリリークとの戦いをご覧ください。主に、FastMMを使用してDelphiのメモリリークを防止/検出する方法を示します。D2007用でしたが、他のバージョンにも関連しています。

于 2009-06-24T00:57:01.977 に答える
4

ここまでで、FastMM のしくみについて適切な回答が得られました。しかし、あなたの実際の質問に関しては、はい、インターフェース化されたオブジェクトは2つの異なる方法でリークする可能性があります.

  1. インターフェイスが属するオブジェクトが _AddRef および _Release メソッドで参照カウントを実装している場合にのみ、インターフェイスは参照カウントされます。一部のオブジェクトはそうではありません。
  2. 循環インターフェース参照がある場合 (インターフェース 1 がインターフェース 2 を参照し、インターフェース 1 がインターフェース 2 を参照する)、参照カウントが 0 になることはありません。これが問題である場合は、この件に関する Andreas Hausladen の最近のブログ記事を参照してください。
于 2009-06-24T01:20:26.513 に答える
2

そのクラスの115個のインスタンスをリークしている場合、リークされているのはそのクラスです。参照するものが占めるメモリではなく、そのクラスが占めるメモリがリークされています。どこかに、TCwcBasicAdapter解放していない115のインスタンスがあります。

さらに、プロパティは、インターフェイスやその他のタイプに関係なく、データを保存しません。フィールドのみがメモリを占有します(コンパイラがクラスに代わって割り当てる隠しスペースもあります)。

だから、はい、あなたは間違った木を吠えています。あなたのメモリリークはどこかにあります。FastMMがメモリリークがあることを通知する場合、リークされた各インスタンスが割り当てられた場所も通知しません。その機能があります。その機能を有効にするには、いくつかの条件付きコンパイルシンボルを調整する必要がある場合があります。

確かに、リークしているのはそのクラスのインスタンスだけではありません。FastMMは、インターフェイスを実装する1つまたは複数のクラスのインスタンスなど、リークしている他のいくつかのことも報告する必要があります。


あなたが追加した関数に基づいて、私はそれが本当にTCwcCDSAdapterNavBaseリークしているのではないかと疑い始めました、そしてそれはあなたがそれを作成するために使用する非定型の方法のためである可能性があります。例外ハンドラーはGetAdapterNav実行されますか?疑わしい; TObject.GetInterface明示的に例外を発生させることはありません。オブジェクトがインターフェースをサポートしていない場合は、を返しますFalse。例外ハンドラーがキャッチできるのは、アクセス違反や不正な操作などです。これらは、とにかくそこでキャッチするべきではありません。

この機能は、次のように直接実装できます。

if Assigned(FDataSet) then
  Result := TCwcCDSAdapterNavBase.Create(...);
于 2009-06-24T01:05:25.797 に答える