1

アプリケーションにメモリリークがあり、実際のソースを見つけることができません。このコード行は、次のようなコントロールにありますDataTableEditor

refreshButton.DataBindings.Add("Enabled", asyncSqlResultsViewer, "CanRefresh", true, DataSourceUpdateMode.Never);

は、データを表示asyncSqlResultsVewerするだけのユーザーコントロールDataGridViewです。データを非同期でロードするために使用されましたが、現在はロードされていません。コントロールは、DataTableEditorを含む別のユーザーコントロールですAsyncSqlResultsVewer。リークはPropertyDescriptor、オブジェクトを存続させているパスの一部として表示されるため、これに関連しているようです。

.netメモリプロファイラーのスクリーンショット

私は.NETMemoryProfilerを使用している初心者ですが、上の行を削除するとリークがなくなります。との境界を削除するとDataBindings.Remove、リークも修正されます。しかし、これは起こるはずですか?はasyncSqlResultsVewer破棄され、私が知る限り、と一緒に参照解除されますDataTableEditor。したがって、他の誰も参照していない限り、それらの間のすべての参照は、それらを存続させてはなりません(右?)。万が一の場合やハックとしてバウンドを削除することはできますが、リークの本当の原因を誰かに教えてもらいたいです。

これが実際のメモリリークであるかどうか疑わしい場合は、DataTableEditor大量のデータを表示するいくつかのを開いたり閉じたりすると、アプリケーションがクラッシュします。また、プロファイラーはオブジェクトが破棄されたと言っていますが、それへの参照はまだあります。

私がこれを理解するのを助けるかもしれない他の情報があれば、私に知らせてください。

編集:私はリークがどこから来るのか知っていると思います。refreshButton上記はこのクラスのインスタンスです:

public class ToolStripBindableButton : ToolStripButton, IBindableComponent, INotifyPropertyChanged
{
    private ControlBindingsCollection dataBindings;

    private BindingContext bindingContext;

    public ControlBindingsCollection DataBindings
    {
        get
        {
            if (dataBindings == null) dataBindings = new ControlBindingsCollection(this);
            return dataBindings;
        }
    }

    public BindingContext BindingContext
    {
        get
        {
            if (bindingContext == null) bindingContext = new BindingContext();
            return bindingContext;
        }
        set { bindingContext = value; }
    }

    public override Image Image
    {
        get { return base.Image; }
        set { SetImage(value); }
    }

    private void SetImage(Image value)
    {
        if (base.Image != value)
        {
            base.Image = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Image"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null) PropertyChanged(this, e);
    }
}

Disposeオーバーライドを追加して実行するとdataBindings.Clear()、リークが修正されます。これは私がすることになっていることですか、それともリークの本当の原因はまだ他の場所にありますか?

4

1 に答える 1

2

あなたはすでにメモリリークの問題に自分で答えたと思います。

私の意見では、リークの原因は更新ボタン (のインスタンスToolStripBindableButton) である可能性が高いと思われます。

が呼び出されると、ToolStripButton.Dispose()必要なすべてのオブジェクトをクリーンアップ/解放する方法を認識します。ただし、クラスをどのように拡張したかを知る方法がないため、クリーンアップを支援することはできません。

継承することを期待ControlBindingsCollectionしていたので、クリーンアップが必要であることを明確にしました。BindingContextIDisposable

protected override void Dispose(bool disposing)
{
  base.Dispose(disposing);

  if (disposing && dataBindings != null)
  {
    dataBindings.Clear();
  }
  dataBindings = null;
  dindingContext = null;
  PropertyChanged = null;
}

問題の原因を見つけたかどうかを判断するのは難しいですが、何らかの方法で破棄/解放/強制終了されていないイベントを監視します.

また、フォーム上のコンポーネントをよく見てください。これらは、IContainer のインスタンスを使用して作成され、WinForms デザイナーがそうしないことを選択できる場合にのみ、自動的に破棄されます。

于 2013-02-14T07:03:54.373 に答える