如果不首先删除侦听器,重新分配数据源是否会导致内存泄漏?

时间:2015-12-02 18:35:00

标签: c# winforms ado.net

我的表格上有两个网格。 每当行在grid1中获得焦点时,其关联的子行将通过ADO.NET从数据库中获取,grid2的DataSource将被重新分配,如下所示:

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

ASIDE:grid1包含很多行,因此我不想在一个(耗时)查询中获取所有父行的子行,然后过滤大数据集儿童行客户端。

当用户使用表单期间多次重新分配本地Children变量和grid2的数据源时,这些匿名事件侦听器会发生什么?不明确删除处理程序会导致内存泄漏吗?

1 个答案:

答案 0 :(得分: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; } 创建的其他对象一起获取垃圾。

我创建了以下测试平台来模拟您的代码正在做什么:

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
}

当我在 Instrumentaion模式中使用Visual Studio中的Performance Explorer运行它并且启用收集.Net对象生存期信息时,这是我的结果:

Object lifetime

正如您所看到的,当分析结束时,所有DataTable实例都返回0,并且适用于在该测试中实例化的所有类型。

如果您保留引用但是在方法结束时最终会有1000个实例,如此测试用例所示:

$("a[data-toggle='tab']").on('shown.bs.tab',function(e) {
         initialize();   // map - function
});

因此,只要您不保留以前使用的实例的引用,您应该没问题。