【问题标题】:Apparent Memory Leak in DataGridViewDataGridView 中的明显内存泄漏
【发布时间】:2009-11-09 16:22:13
【问题描述】:

如何强制 DataGridView 释放其对绑定 DataSet 的引用?

我们在 DataGridView 中显示了一个相当大的数据集,并注意到在 DataGridView 关闭后资源没有被释放。如果用户反复查看此报告,他们最终会遇到内存不足异常。 ANTS Memory Profiler 确认尽管dgv.DataSource 被设置为空,DGV 仍持有引用。

【问题讨论】:

    标签: c# .net winforms memory-leaks


    【解决方案1】:

    您是否在 DataGridView 上注册了任何事件,例如 OnClick?确保取消注册所有事件,否则不会被垃圾回收

    【讨论】:

    • 这不是完全正确的; DataGridView 可以通过其事件看到 out - 因此,如果 DataGridView 正在被处置,则其事件将被取消。一个更好的问题是:什么可以看到(旧的)DataGridView...
    • 是的,有很多事件。我在别处读过这篇文章,但似乎不是原因。
    【解决方案2】:

    调用这个来清除DataGridView1:

    datagridview1.DataSource = null;
    datagridview1.Rows.Clear();
    GC.Collect();
    

    我如何使用它?

    我从DataGridView1导入数据,然后研究内容并转移到DataGridView2

    所以它使用了 2.4GB 的内存,然后在调用 Clear 之后,它降到了正常水平——对我来说是 128KB。

    【讨论】:

      【解决方案3】:

      我们已经在 datagridviews 中看到了这种行为,这些 datagridviews 的数据源包含大量图像,其中 datagridview 被重复加载。将 datagridview 的 DataSource 设置为 null 并对数据源执行 Dispose 并在每次加载之前执行 GC.Collect 似乎可以处理泄漏。

      【讨论】:

        【解决方案4】:

        你要关闭整个Form吗?还是只是DataGridView?我想知道这是否是BindingContext 中的一些缓存。您可以尝试使用每个 DataGridView 的新绑定上下文吗?

        还有;与往常一样,仔细检查事件等 - 特别是任何使用捕获的变量,因为这是添加依赖项的一种微妙方式(注意捕获范围意味着如果你有复杂的匿名方法 / lambda,你可能捕获的比你想象的更多)。

        您可能需要进入分析器或 windbg 才能找到剩余的参考。

        【讨论】:

        • 数据网格位于每次都会关闭的表单上。当用户运行新报告时,会创建一个新实例。
        【解决方案5】:

        强制DataGridView释放资源的技巧是通过中间对象BindingSource进行绑定。

        代码如下所示:

        ...
        DataGridView dgvQueryResults;
        DataTable m_dataTable;
        BindingSource m_binder;
        
        public void PopulateView()
        {
          ...
          // Bind the data source through and intermediary BindingSource
          m_binder.DataSource = m_dataTable;
          dgvQueryResults.DataSource = m_binder;
          ...
        }
        
        
        /// <summary>
        /// Frees lindering resources. Sets data bindings to null and forces 
        /// garbage collection.
        /// </summary>
        private void ResetDataGridView()
        {
          dgvQueryResults.DataSource = null;
        
          if (null != m_binder) m_binder.DataSource = null;
          m_binder = null;
        
          dataTable = null;
        
          // Force garbage collection since this thing is a resource hog!
          GC.Collect ();
        
          m_binder = new BindingSource ();
        }
        
        ...
        

        【讨论】:

        • 使用BindingSource 有很多很好的理由,但这不是其中之一。如果对象因为注册了事件而没有被释放,那么使用BindingSource 根本无法解决问题。另外:拨打GC.Collect() 的理由很少,这不是其中之一。
        • 微软在此建议使用 BindingSource:connect.microsoft.com/VisualStudio/feedback/… 在这种情况下调用 GC.Collect() 是必要的,因为用户点击报告的速度可能比 GC 释放资源的速度更快,并且应用程序很快就会崩溃并显示内存异常。当然,报告功能可以重写以更好地发挥作用。顺便说一句,这一切都是由于经典没有使用真实数据集进行测试 8]
        【解决方案6】:

        您不应将 DataGridView 设置为 null。您应该在 DataGridView 上调用 dispose 以允许它正确清理自己,而不是向 GC 添加更多工作来处理它。

        此外,如果您有任何对 DataGridView 的根引用,它将永远不会被释放(即使您调用 Dispose())。 GC 认为它还活着。您应该检查对它的任何根引用 - 即事件处理程序、静态引用等,并在调用 Dispose() 之前先删除它们。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-14
          • 1970-01-01
          • 1970-01-01
          • 2012-06-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多