2015-12-02 3 views
5

私のフォームに2つのグリッドがあります。 行がGRID1にフォーカスを取得するたびに、それに関連する子行がADO.NETを介してデータベースからフェッチされ、次のようにgrid2のDataSourceが再割り当てされています脇リスナーが最初に削除されないと、データソースを再割り当てするとメモリリークが発生しますか?

 //focused row changed handler 
    DataTable Children = FetchChildren(parentid); 
    grid2.DataSource = Children.DefaultView; 
    Children.RowDeleted += (sndr, evt) => 
     { 
     // 
     }; 

:GRID1は、多くの行が含まれているので、私はしたくありません1つ(時間のかかる)クエリですべての親行の子ローをフェッチし、次にフィルタ大きなローのデータセットのクライアント側をクライアント側にフェッチします。

ユーザーがフォームを使って作業しているときに、ローカルのChildren変数とgrid2のデータソースが何度も再割り当てされると、そのような匿名のイベントリスナーにはどうなりますか?ハンドラを明示的に削除してもメモリリークが発生しないか?

答えて

1

いいえ、表示されるコードでは、メモリリークが発生しません。オブジェクトがガベージコレクションされないことを示すためにこの用語を使用することを前提としています。匿名イベントハンドラの代理人は、範囲外になったDataTableによって作成された残りのオブジェクトでガベージコレクションを長く取得する参照です。私はあなたのコードが何をしているかをシミュレートするために、以下のテスト・リグを作成しました

static object DataSource; 

static void Main(string[] args) 
{ 
    Test1(); 
    // clean up 
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true); 
    GC.WaitForPendingFinalizers(); 
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true); 
} 

static void Test1() 
{ 
    for (var i = 0; i < 1000; i++) 
    { 
     var dt = FetchChildren(i); 
     DataSource = dt.DefaultView; 
     dt.RowDeleted += (s, e) => 
     { 
      var table = (DataTable)s; 
      Trace.WriteLine(String.Format("{0}:{1}:{2}", e.Action, e.Row.RowState, table)); 
     }; 
     // do work 
     var dv = (DataView)DataSource; 
     dv.Delete(5); 
    } 
    DataSource = null; 
} 

// create a useful datatable 
static DataTable FetchChildren(int parent) 
{ 
    var dt = new DataTable(); 
    dt.Columns.Add("key", typeof(int)); 
    dt.Columns.Add("guid", typeof(string)); 

    for(var i=0; i<10; i++) 
    { 
     var row = dt.NewRow(); 
     row[0] = parent; 
     row[1] = Guid.NewGuid().ToString("N"); 
     dt.Rows.Add(row); 
    } 

    return dt; 
} 

私はInstrumentaionモードでのVisual Studioでのパフォーマンスエクスプローラでと収集でこれを実行すると。あなたはすべてのDataTableのインスタンスを見ることができるように

Object lifetime

:ネットオブジェクトの寿命情報が、これは私の結果であり、有効プロファイリングが終了すると0に戻ります。これは、そのテストでインスタンス化されたすべてのタイプに適用されます。あなたは、インスタンスへの周りの参照を保持しないように、限り

static void Test2() 
{ 
    for (var i = 0; i < 1000; i++) 
    { 
     var dt = FetchChildren(i); 
     var local = DataSource; // our previous DataTable 
     dt.RowDeleted += (s, e) => 
     { 
      var table = (DataTable)s; 
      Trace.WriteLine(String.Format("{0}:{1}:{2}", e.Action, e.Row.RowState, local)); // use it here 
     }; 
     DataSource = dt.DefaultView; 
     // do work 
     var dv = (DataView)DataSource; 
     dv.Delete(5); 
    } 
    //DataSource = null; // don't dereference 
} 

:このテストケースのように、あなたがメソッドの最後に1000のインスタンスで終わることができますしかし、周りの参照を保持する場合

以前はあなたは大丈夫でしょう。

+0

パフォーマンス・エクスプローラーに関する有益な情報をありがとう – Tim

関連する問題