views:

306

answers:

5

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.Delegate.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
+4  A: 

Yes, the reference will stay alive unless you unsubscribe from the event:

someObject.SomeEvent -= SomeDelegate;
Ed Swangren
what if I have a big complex object with multiple delegates subscriptions/unsubscriptions, finally in the Dispose of this object I want to "let die" all links to this delegate.
serhio
Then you can implement IDisposable.
Ed Swangren
yes, and what should I write in the Dispose method for that delegate. , maybe `System.Delegate.RemoveAll(myDelegate, myDelegate)` would help?
serhio
You would do just as I have sown in my example.
Ed Swangren
Hmmm...someone downvoted this, I wonder why...
Ed Swangren
+1  A: 

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:

ewernli
in other words, you mean that B will not be collected as long as ADelegate points to it?..
serhio
Yes, I think it's the case
ewernli
+1  A: 

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.

Carra
+2  A: 

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.

mrwayne
A: 

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.

dh