Can Delegates cause memory leaks?
I mean, by e.g. if a class A
contains a ADelegate
and the latter points to the BMethod
(of B
class) can this prevent the A class or B class collection by the GC?
If so, how can we "free" delegates (setting ADeletate = Nothing
/ null?)
How do you comment this one:
//Class A Finalize, containing ADelegateInstance as ADelegate'
protected override void Finalize()
{
ADelegateInstance =
(ADelegate)System.De开发者_如何学运维legate.RemoveAll(
ADelegateInstance, ADelegateInstance);
ADelegateInstance = null;
base.Finalize();
}
'Class A Finalize, containing ADelegateInstance as ADelegate'
Protected Overrides Sub Finalize()
ADelegateInstance = _
CType(System.Delegate.RemoveAll(ADelegateInstance, ADelegateInstance), _
ADelegate)
ADelegateInstance = Nothing
MyBase.Finalize()
End Sub
Yes, the reference will stay alive unless you unsubscribe from the event:
someObject.SomeEvent -= SomeDelegate;
Just having a reference is not enough to cause a memory leak. Consider the following.
If a thread spawns 3 objects (where -> denotes a reference), A -> B -> C -> A
If A is not referenced by the thread, all are collected. Circular references are dealt with by the GC.
However, this also obviously means, if a delegate contains a reference to an object, and that object with the delegate is still referenced, then the delegate function will not be cleaned up.
That would give you the following below.
A - (object with delegate) B - object containing a function reference.
When A falls out of scope, then B will to.
AFAIK, the context that a closure/delegates refers to can indeed not be garbage collected as long as the closure/delegate is still referenced -- otherwise it would lose its context.
Taking the example for this answer, we see that a delegate can reference the variable inneri
in the context of the object. So the object which actually holds inneri
can not be garbage collected until the delegate is no more referenced, in this case, until the Button
has been garbage collected.
for (int i = 0; i < 7; i++)
{
var inneri = i;
Button newButton = new Button();
newButton.Text = "Click me!";
newButton.Click += delegate(Object sender, EventArgs e)
{
MessageBox.Show("I am button number " + inneri);
};
this.Controls.Add(newButton);
}
Related posts:
- Captured variable in a loop in C#
- Closures in C# event handler delegates?
- What are 'closures' in .NET?
If A contains a delegate to a function in B then A will not be destroyed by the GC.
It's a good idea to always put in a "mydelegate -= B.method" everytime you write a "mydelegate += B.method".
Although it's not a real memory leak as the objects can still be reached.
There was a situation when in ASP.NET application a singleton was used. And for some reason it used to subscribe to events of controls. The fact that it was a singleton (containing reference to itself) did not allow GC to collect it, on the other hand that singleton have never removed subscriptions to control events. That caused a permanent growth of memory consumption: controls used to serve a single request where not cleaned by GC due to existing reference from the singleton, new controls where created for each new request.
精彩评论