Unbinding from a DataGridView, memory leak?
Using VS Express 2008 and .NET2.0.
I have a DataGridView which has as its .DataSource a BindingSource, which in turn has its .DataSource set to a BindingList<> which contains some classes.
All works well, and I potentially have a list of several thousand items, and hence several thousand rows on the grid.
When I wish to disconnect binding, clear the list and hence clear the grid, I am setting the grid DataSource property to Nothing, and calling .Clear in the BindingSource.
However, it appears that when I do this, the memory usage (Private bytes) does not reduce until TWO full GC's occur. (Both metrics checked with PerfMon.)
I can only surmise that the original row instances in the grid are hanging around and making it on to the Finalizer queue perhaps?
Is there anything I can do about this, or is it expected behaviour? I'm not sure if setting the DataSource property to Nothing is enough to 'purge' the grid properly.
Using Reflector, I notice that DataGridViewRow inherits Dispose from it's base class, so do I have to call this somehow, or should the act of unbinding do this automatically?
(The classes in the list are purely managed, and have nothing that requires Dispose calling on them.)
Thanks for any help.
Re: Unbinding from a DataGridView, memory leak?
How are you creating the BindingList in the first place? Is there maybe an array or the like that also has a reference to the items? It sounds like those items are referenced somewhere other than the BindingList, otherwise I would expect them to be cleaned up on the first collection.
Re: Unbinding from a DataGridView, memory leak?
Quote:
Originally Posted by
jmcilhinney
...I would expect them to be cleaned up on the first collection.
This is what I expected too.
I am using the BindingList as follows. (Please forgive the C# syntax...)
Code:
myClassList = new BindingList<MyClass>();
bindingSource.DataSource = myClassList;
dgv.DataSource = bindingSource;
.
.
myClass = new MyClass();
myClassList.Add(myClass);
The instances of MyClass only get added to the list, they do not get added to an array, or individually referenced anywhere. (At least, not intentionally.)
I guess I may have to make a test project to investigate further.
Re: Unbinding from a DataGridView, memory leak?
Interestingly, if I bind a list that is already filled, and do not add to it, the memory is reclaimed correctly when the binding is removed, and the list is cleared.
The problem occurs when I bind the list, and then periodically add to it. (This is what I would like to do, as I am logging data from a machine controller and I want to see the additions to the grid in real time.) The additions could be as frequent as ecery 500ms, but typically around one every second.
It appears that in this case the rows are not being cleaned up properly when binding is removed.
Not sure where to go from here? Any thoughts appreciated.
Re: Unbinding from a DataGridView, memory leak?
If you're using a BindingList, is there really any need for a BindingSource? If you're not using the navigation methods then probably not. I wonder whether that would make a difference?
Re: Unbinding from a DataGridView, memory leak?
Good suggestion, had not thought to try that, although it appears to exhibit the same behaviour.
As a test, I am manually filling a BindingList and then binding it directly to the grid.
The grid displays correctly, and after unbinding and clearing the BindingList, the memory is recalimed on the first full GC. (I put a button on the form to force a GC.Collect.)
If however I bind an empty list to the grid first, and then fill it, the grid still displays correctly, (although it does take longer to display). When I unbind and the clear the list, I need to call GC.Collect twice before the memory is reclaimed. Hmmm.
To clarify, the memory values I am checking are 'Private bytes' and 'Bytes in all heaps' and I am targetting .NET2.0 with sp2.
Re: Unbinding from a DataGridView, memory leak?
Further tests indicate that additons to the list before binding it to the grid are reclaimed after one GC when binding is removed, while additions made to the list after databinding take two GC's when unbound.
This can't be expected behaviour, can it?? :ehh:
Re: Unbinding from a DataGridView, memory leak?
I can only assume that there are additional references to those new items that take two collections to clean up. Where exactly those references are I couldn't say.
Re: Unbinding from a DataGridView, memory leak?
This is my entire test project. One form, one DataGridView and three buttons:
I have also tried binding to a list of Integers in case something odd was occurring with my custom class.
vb Code:
Private myList As BindingList(Of TrackedSet)
Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs)
If (myList Is Nothing) Then
myList = New BindingList(Of TrackedSet)
End If
' Binding here needs two GC's to reclaim memory when unbinding
' dgv.DataSource = myList
Dim i As Integer
For i = 0 To 50000
myList.Add(New TrackedSet(i, "00000000001,123,abc"))
Next i
' Binding here allows memory to be reclaimed ok when unbinding
dgv.DataSource = myList
End Sub
Private Sub button2_Click(ByVal sender As Object, ByVal e As EventArgs)
dgv.DataSource = Nothing
myList.Clear
myList = Nothing
End Sub
Private Sub button3_Click(ByVal sender As Object, ByVal e As EventArgs)
GC.Collect
End Sub