Apparent Memory Leak in DataGridView

2019-04-29 18:46发布

How do you force a DataGridView to release its reference to a bound DataSet?

We have a rather large dataset being displayed in a DataGridView and noticed that resources were not being freed after the DataGridView was closed. If the user repeatedly views this report they eventually get an out of memory exception. ANTS Memory Profiler confirmed that the DGV is holding a reference despite dgv.DataSource being set to null.

6条回答
时光不老,我们不散
2楼-- · 2019-04-29 18:57

Call this to clear DataGridView1:

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

How I use it?

I imported data from to DataGridView1 and then studied the content and transferred it to DataGridView2.

So it used 2.4GB of memory and then, after calling Clear, it dropped to normal - for me to 128KB.

查看更多
手持菜刀,她持情操
3楼-- · 2019-04-29 19:01

We've seen this behavior with datagridviews that have a datasource that contains a lot of images where the datagridview gets loaded repeatedly. Setting the DataSource for the datagridview to null and doing a Dispose on the datasource and a GC.Collect prior to each load seems to handle the leak.

查看更多
兄弟一词,经得起流年.
4楼-- · 2019-04-29 19:02

The trick to forcing the DataGridView to release resources is to do the binding through the intermediary object BindingSource.

The code then looks something like this:

...
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 ();
}

...
查看更多
等我变得足够好
5楼-- · 2019-04-29 19:14

Are you closing down the entire Form? or just the DataGridView? I'm wondering if this is some caching in the BindingContext. You could try using a new binding-context per DataGridView?

Also; as always, double check events etc - in particular any using captured variables, as that is a subtle way of adding a dependency (note the capture scopes mean you might be capturing more than you think if you have complex anonymous methods / lambdas).

You might need to drop into profilers or windbg to find the remaining reference.

查看更多
Fickle 薄情
6楼-- · 2019-04-29 19:20

You shouldn't set the DataGridView to null. You should call dispose on the DataGridView instead to allow it to properly clean itself up instead of adding more work to the GC to handle it.

Also, if you have any rooted references to the DataGridView, it will never be disposed (even if you call Dispose()). The GC thinks it's still alive. You should check for any rooted references to it - i.e. event handlers, static reference, etc. and remove those first before calling Dispose().

查看更多
SAY GOODBYE
7楼-- · 2019-04-29 19:23

Do you have any events registered on the DataGridView like OnClick? Make sure you unregister all events, otherwise it will not be garbage collected

查看更多
登录 后发表回答