question

ReutMeiselman-3014 avatar image
0 Votes"
ReutMeiselman-3014 asked JackJJun-MSFT edited

BindingList<T>, DataGridView and DataGridViewRow.Dispose

Hi,
I have BindingList<T> that is bound to DataGridView, via BindingListView<T> like:

 BindingList<MyItem> _bindingListMain = new BindingList<MyItem>();
 BindingListView<MyItem> _bindingListViewMain = new BindingListView<MyItem>(_bindingListMain);
 dataGridViewItems.DataSource = _bindingListViewMain;

Every number of items, the list is cleared, with

 _bindingListMain.Clear();

What happens with the bound DataGridViewRows? Is their Dispose function gets called? Should I call their Dispose by myself?
I get OutOfMemory exception after my application is up for a few hours and I am looking for the root cause.

Thanks












dotnet-csharp
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

How many records?

0 Votes 0 ·

Every 10 milliseconds a new item is added (and therefore a new row), and every 200 records I clear the list.

0 Votes 0 ·

Have tried re-creating the BindingList rather than clearing it?

0 Votes 0 ·

@ReutMeiselman-3014, the problem How can I Dispose a DataGridViewRow containing a databound DataGridViewComboBoxCell? is similar to your problem. also the owner provide a code example to solve the problem about dispose the DataGridViewRow.


0 Votes 0 ·
Paul-5034 avatar image
0 Votes"
Paul-5034 answered ReutMeiselman-3014 commented

Have you tried using a memory profiler to figure out the cause or is this just a hypothesis? If you haven't profiled it I'd recommend using something like ANTS memory profiler (there's a 14 day trial period) & it's really easy to use:
https://www.red-gate.com/products/dotnet-development/ants-memory-profiler/

If you're running out of memory you should hopefully get a clear indication of where the memory leak is occurring.

· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I haven't tried a memory profiler (I will though...), but it looks like the datagridview has something to do with it, cause if I shut it down the memory remains pretty much the same.

0 Votes 0 ·
karenpayneoregon avatar image
0 Votes"
karenpayneoregon answered

Okay, I took an existing code sample using a BindingSource and DataTable and changed to using a BindlingList<Customer>, BindingSource to a DataGridView as shown below. Fired the application using JetBrains dotMemory.

Overall I didn't match exactly what you are doing but instead the following shows no memory issues. If you were to do the same and still have issues best guess is there may be leaks with your DataGridView events which I've heard to be an issue which complicates issues. Perhaps if there are still leaks consider going to a ListView.

Results from three sessions, all were within one percent of each other and in each case used a in-house custom automation tool to click the load button over 100 times.

145531-snapshots1.png


 using System;
 using System.ComponentModel;
 using System.Threading.Tasks;
 using System.Windows.Forms;
 using LoadDataGridViewProgressBar.Classes;
    
 namespace LoadDataGridViewProgressBar
 {
     public partial class BindingListForm : Form
     {
         private BindingSource _customersBindingSource = new BindingSource();
         private BindingList<Customer> _customersBindingList = new BindingList<Customer>(); 
         public BindingListForm()
         {
             InitializeComponent();
             Shown += OnShown;
         }
         private async void OnShown(object sender, EventArgs e)
         {
             await PopulateData();
         }
         private async Task PopulateData()
         {
             var (exception, customers) = await Operations.LoadCustomerList();
    
             if (exception == null)
             {
                 _customersBindingList = null;
                 _customersBindingSource = null;
                 customerDataGridView.DataSource = null;
    
                 GC.Collect();
                 await Task.Delay(500);
    
                 _customersBindingList = new BindingList<Customer>(customers);
                 _customersBindingSource = new BindingSource { DataSource = _customersBindingList };
                 customerDataGridView.AutoGenerateColumns = false;
                 customerDataGridView.DataSource = _customersBindingSource;
                 customerDataGridView.ExpandColumns(true);
             }
             else
             {
                 // Decide how to handle any errors
             }
         }
    
         private async void LoadDataGridViewButton_Click(object sender, EventArgs e)
         {
             await PopulateData();
         }
     }
 }

Full source using BindingListForm.

145513-figure1.png



snapshots1.png (92.6 KiB)
figure1.png (27.7 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

ReutMeiselman-3014 avatar image
0 Votes"
ReutMeiselman-3014 answered

Well, it looks like when I clear the binding list, the bound rows aren't disposed, and therefore the memory kept growing.
After adding:

 foreach (DataGridViewRow row in dataGridViewItems.Rows)
 {
         row.Dispose();
 }
 _bindingListMain.Clear();
 GC.Collect();

The memory remained low and stable.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.