Event handlers can easily lead to memory leaks, because the event's invocation list holds a reference to the event handling instance, so that the event handling instance cannot be garbage collected, if the event source is still alive.
But consider the following code:
public class SomeClass
{
public event EventHandler SomeEvent;
}
public class MyClass
{
public MyClass(SomeClass source)
{
//VERSION 1
source.SomeEvent += OnSomeEvent;
//VERSION 2
void localHandler(object s, EventArgs args) { Console.WriteLine("some action with(out) any references"); }
source.SomeEvent += localHandler;
//VERSION 3
var x = new object();
source.SomeEvent += (s, e) => { Console.WriteLine("some event fired, using closure x:" + x.GetHashCode()); };
//VERSION 4
source.SomeEvent += (s, e) => { Console.WriteLine("some action without any references"); };
}
private void OnSomeEvent(object sender, EventArgs e)
{
//...
}
}
My assumptions/questions why the different event handling versions may cause a memory leak:
- Version 1: Because the invocation target clearly references the instance of
MyClass
. - Version 2: Because the reference to
localHandler
implies a reference to the instance ofMyClass
- except, maybe, if the code insidelocalHandler
has no references to the instance ofMyClass
? - Version 3: Because the lambda contains a closure, which itself is a reference to the instance of
MyClass
- or is it? - Version 4: Because the lambda does not reference the instance of
MyClass
, this may not cause a leak?
And, follow-up questions to versions 3 and 4:
- Where is the "magic helper object" that .Net creates for the lambda/closure stored and does it (always) include a reference that would keep the instance of
MyClass
alive? - If lambda event handlers can leak, they should only be used in scenarios where this is not a problem (e.g.
MyClass
instances outliveSomeClass
instances), because they cannot be removed using-=
?
EDIT: This post (with the original title "When can event handlers cause memory leaks?") was suggested as a duplicate, of Why and How to avoid Event Handler memory leaks?, but I disagree, because the question was directed at lambda event handlers specifically. I rephrased the question/title to make this more clear.