I have a memory leak in my application that I cannot find the real source of. There is this line of code in a control called DataTableEditor
:
refreshButton.DataBindings.Add("Enabled", asyncSqlResultsViewer, "CanRefresh", true, DataSourceUpdateMode.Never);
The asyncSqlResultsVewer
is just a user control with a DataGridView
that shows data. Used to load the data asynchronously but it doesn't anymore. The DataTableEditor
control is another user control that contains an AsyncSqlResultsVewer
. The leak seems related to this because it shows a PropertyDescriptor
as part of the path that is holding the object alive:
I'm a newbie using the .NET Memory Profiler but the thing is, removing the line above gets rid of the leak. Removing the bound with DataBindings.Remove
also fixes the leak. But, is this supposed to happen? The asyncSqlResultsVewer
is disposed and as far as I know de-referenced together with the DataTableEditor
, so every reference among them shouldn't keep them alive anymore as long as no one else references any of them (right?). I can still remove the bound just in case or as a hack, but I'd like someone to help me figure out what the real cause of the leak is.
In case you're in doubt this is an actual memory leak, the application crashes after opening and closing several DataTableEditor
s that show a large amount of data. Also, the profiler is telling me the object has been disposed but there are still references to it.
If there is any other piece of information that might help you help me figure this out please let me know.
Edit: I think I know where the leak may come from. refreshButton
above is an instance of this class:
public class ToolStripBindableButton : ToolStripButton, IBindableComponent, INotifyPropertyChanged
{
private ControlBindingsCollection dataBindings;
private BindingContext bindingContext;
public ControlBindingsCollection DataBindings
{
get
{
if (dataBindings == null) dataBindings = new ControlBindingsCollection(this);
return dataBindings;
}
}
public BindingContext BindingContext
{
get
{
if (bindingContext == null) bindingContext = new BindingContext();
return bindingContext;
}
set { bindingContext = value; }
}
public override Image Image
{
get { return base.Image; }
set { SetImage(value); }
}
private void SetImage(Image value)
{
if (base.Image != value)
{
base.Image = value;
OnPropertyChanged(new PropertyChangedEventArgs("Image"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null) PropertyChanged(this, e);
}
}
Adding a Dispose
override and doing dataBindings.Clear()
fixes the leak. Is this something I'm supposed to do or is the real cause of the leak still elsewhere?
I belive that you already answered the memoryleak problem yourself.
In my opinion it seems likely that cource of the leak is the refreshbutton (instance of ToolStripBindableButton
).
When the ToolStripButton.Dispose()
is called it knows how to cleanup/release all of its objects that requirs so. However it have no way of knowing how you extented the class, and therefore it cannot help you clean up.
I would have expected ControlBindingsCollection
and BindingContext
to inherit IDisposable
thereby making it clear that cleanup was needed.
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing && dataBindings != null)
{
dataBindings.Clear();
}
dataBindings = null;
dindingContext = null;
PropertyChanged = null;
}
It's hard to tell wheather you found the souce of the problem, but I would keep an eye on any events not beeing disposed/released/killed-somehow.
Also keep a close look at your components on your forms. Theise only gets disposed automatic, if the are created with an instance of IContainer, and the WinForms designer can choose not to do so.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.