Delphi 2009-インターフェイスプロパティによりメモリリークが発生する可能性はありますか?

StackOverflow https://stackoverflow.com/questions/1035915

質問

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)
役に立ちましたか?

解決

FastMMは、何がリークされ、どこで作成されたかを示します。
それは本当の犯人にそれを絞り込むのを助けるでしょう:誰が何を漏らしているのですか?

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

編集:ICwcCDSAdapterNavを実装しているオブジェクトのコードを見なければ、実際に参照カウントされているかどうかはわかりません。
TInterfacedObjectから派生していない場合チャンスは参照カウントされないこの自動解放に依存できない ...

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

他のヒント

FastMMの仕組みについては、これまでにいくつかの良い答えがあります。しかし、実際の質問については、はい、インターフェイスオブジェクトは2つの異なる方法でリークする可能性があります。

  1. インターフェイスは、所属するオブジェクトが_AddRefメソッドと_Releaseメソッドで参照カウントを実装している場合にのみ参照カウントされます。一部のオブジェクトはそうではありません。
  2. 循環インターフェイスの参照がある場合(インターフェイス1はインターフェイス2を参照し、インターフェイス1はインターフェイス1を参照します)、参照カウントは0にはなりません。これがあなたの問題であるならば、私はAndreas Hausladenのこのテーマに関する最近のブログ投稿を参照します。

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

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

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

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


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

次のように、その機能をより直接実装できます。

if Assigned(FDataSet) then
  Result := TCwcCDSAdapterNavBase.Create(...);
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top