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:
MyClass
.localHandler
implies a reference to the instance of MyClass
- except, maybe, if the code inside localHandler
has no references to the instance of MyClass
?MyClass
- or is it?MyClass
, this may not cause a leak?And, follow-up questions to versions 3 and 4:
MyClass
alive? MyClass
instances outlive SomeClass
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.
Disclaimer : I can't guarantee this is 100% truth - your question is quite deep and I could make a mistake.
However, I hope it will give you some thoughts or directions.
Let's consider this question according CLR
memory organization:
Local method variables and method parameters are stored in the method stack frame in memory (except they declared with ref
keyword).
Stack stores value types and reference-type variables references which point on objects in heap.
Method stack frame is exists while method execution, and local method variables will dissappear with stack frame after method ended.
Except if local variables were captured one way or another, it also relates to compiler work, you can read about it at Jon Skeet's website:
http://jonskeet.uk/csharp/csharp2/delegates.html#captured.variables
Version 1 : OnSomeEvent
method is member of MyClass
and it will captured by Someclass source
instance, until delegates that refers on this method will not be removed from event. So, MyClass
instance that was created in constructor, placed in heap and holds this method will not be collected by GC
until its method reference will not be removed from event.
Compiler compiles lambda by specific way, please read Implementation example paragraph fully:
https://github.com/dotnet/csharplang/blob/master/spec/conversions.md#anonymous-function-conversions
Version 4 : 2 links I provided give a kick lambda will be compiled to MyClass
method, which will be captured by SomeClass
instance as in Version 1
Version 2 : I don't know nuances about how local methods will be compiled, but it should be same as in Version 4 (and, therefore, Version 1 ).
Version 3 : All local variables will be captured by interesting way.
You have 'object x' also, so compiler generated class will be created, which will contain public field public object x;
and method which will be translated from your lambda (see Implementation example paragraph).
So, I think in Versions 1,2,4 will be internally the same: MyClass will contain the method which will be used as event handler.
In Version 3 compiler generated class will be created and it will hold your local variable and method translated from lamdba.
Any instance of any class will not be collected by GC until SomeClass
event has its method in invocation list.
source.SomeEvent = null
. https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/events/how-to-subscribe-to-and-unsubscribe-from-events#unsubscribing
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.