I'm working in C# and my workplace has some code standards. One of them is that each event handler we connect (such as KeyDown) must be disconnected in the Dispose method. Is there any good reason for that?
Unless you expect the publisher of the event to outlive the subscriber, there's no reason to remove the event handler, no.
This is one of those topics where folk lore has grown up. You really just need to think about it in normal terms: the publisher (e.g. the button) has a reference to the subscriber. If both the publisher and the subscriber will be eligible for garbage collection at the same time anyway (as is common) or if the publisher will be eligible for garbage collection earlier, then there's no GC issue.
Static events cause a GC problem because they're effectively an infinitely-long-lived publisher - I would discourage static events entirely, where possible. (I very rarely find them useful.)
The other possible issue is if you explicitly want to stop listening for events because your object will misbehave if the event is raised (e.g. it will try to write to a closed stream). In that case, yes, you should remove the handler. That's most likely to be in the case where your class implements IDisposable already. It would be unusual - though not impossible - for it to be worth implementing IDisposable just to remove event handlers.
Well, perhaps, the standard was proposed as a defensive practice against memory leaks. I can't say, this is a bad standard. But, I personally prefer to disconnect event handler ONLY where needed. In that way, my code looks clean and less verbose.
I have written a blog explaining how event handler causes a memory leak and when to disconnect; https://www.spicelogic.com/Blog/net-event-handler-memory-leak-16. Here, I will summarize the explanation to address your core question.
C# Event Handler operator is actually a reference injector:
In C# += operator looks very innocent and many new developers do not get the idea that the right-hand side object is actually passing it's a reference to the left-hand side object.
Event publisher protects event subscriber:
So, if an object gets a reference to another object, what is the problem? The problem is that, when the garbage collector comes to clean up and find an object that is important to keep in memory, it will not clean up all objects that are also referenced by that important object. Let me make it simple. Say, you have an object named "Customer". Say, this customer object has a reference to the CustomerRepository object so that the customer object can search the repository for all of its Address objects. So, if the garbage collector finds that the customer object is needed to be alive, then the garbage collector will also keep the customer repository alive, because, the customer object has a reference to the customerRepository object. Which makes sense as the customer object needs the customeRepository object to function.
But, does an event publisher object needs an event handler to function? NO, right? the event publisher is independent of the event subscriber. Event publishers should not care if an event subscriber is alive or not. When you use the += operator to subscribe to an event of an event publisher, the event publisher receives a reference of the event subscriber. The garbage collector thinks, the event publisher needs the event subscriber object to function, so it does not collect the event subscriber object.
In that way, the event publisher object "a" protects the event subscriber object "b" from being collected by the garbage collector.
Event publisher object PROTECTS the event subscriber object as long as the event publisher object is alive.
So, if you detach the event handler, then the event publisher does not hold the reference of the event subscriber, and the garbage collector can freely collect the event subscriber.
But, do you really need to detach the event handler all the time? The answer is No. Because many event subscribers are really supposed to be living in the memory as long as the event publisher lives.
A Flow Chart to make the right decision:
Most of the time, we find the event subscriber object is as important as the event publisher object and both are supposed to be living at the same time.
Example of a scenario where you do not need to worry:
For example, a button click event of a window.
Here, the event publisher is the Button, and the event subscriber is the MainWindow. Applying that flow chart, ask a question, does the Main Window (event subscriber) supposed to be dead before the Button (event publisher)? Obviously No. Right? That won't even make sense. Then, why worry about detaching the click event handler?
An example when an event handler detachment is a MUST:
I will provide one example where the subscriber object is supposed to be dead before the publisher object. Say, your MainWindow publishes an event named "SomethingHappened" and you show a child window from the main window by a button click. The child window subscribes to that event of the main window.
And, the child window subscribes to an event of the Main Window.
When the user clicks a button in a MainWindow, the child window shows up. Then the user closes the child window when he/she finishes the task from the child window. Now, according to the flow chart I provided if you ask a question "Does the child window (event subscriber) supposed to be dead before the event publisher (main window)? The answer should be YES. Right? Then, make sure to detach the event handler when the task of the child window is done. A good place is the Unloaded event of the ChildWindow.
Validating the concept of memory leak:
I have profiled this code using the dotMemory Memory profiler software from Jet Brains. I started the MainWindow and clicked the button 3 times, which shows a child window. So, 3 instances of the Child Window showed up. Then, I have closed all the child windows and compared a snapshot before and after the child window appearance. I found that 3 objects of the Child Window were living in the memory even I have closed all of them.
Then, I have detached the event handler in the Unloaded event of the child window, like this:
Then, I have profiled again, and this time, wow! no more memory leak caused by that event handler.
I had a major GDI leak in my application if I didn't unregister the event handlers in the Dispose() of a user control that was being dynamically created and destroyed. I found the following in the Visual Studio 2013 help, in the C# Programming Guide. Note the stuff I have put in italics:
How to: Subscribe to and Unsubscribe from Events
...snip...
Unsubscribing
To prevent your event handler from being invoked when the event is raised, unsubscribe from the event. In order to prevent resource leaks, you should unsubscribe from events before you dispose of a subscriber object. Until you unsubscribe from an event, the multicast delegate that underlies the event in the publishing object has a reference to the delegate that encapsulates the subscriber's event handler. As long as the publishing object holds that reference, garbage collection will not delete your subscriber object.
Note that in my case both the publisher and the subscriber were in the same class, and the handlers are not static.
One reason to do it I faced was that it affected assembly unloadability
Related
At work, my old boss would insist we programmatically assign and remove event handlers from our controls in the code behind, rather than simply double clicking a button (for example).
We'd have an AttachEvents() and DetachEvents() method on every single form. I don't remember his explanation as to why this is allegedly better than assigning it from the Design View, and he's since been transferred to a different project. My new manager doesn't know.
I thought he said it had something to do with events not properly being removed from memory, but I really don't know.
So: What is the benefit of doing it this way?
Performance-wise they are the same.
But doing it in the code behind is a much neater way since you control when to AttachEvents() or DetachEvents()
But you have to be careful in terms of avoiding any duplicate event wire ups. These in turn might lead up eating memory, but prominently they would cause performance issues since the event handler would be called as many times as it was wired up.
Some event handlers such as timers need to be removed before leaving a form otherwise they would still fire, for example
timer.Elapsed += ...
and
timer.Elapse -= ...
Probably a good and clear way to remember to do it in this way.
Other than the implications of your own architecture, there's no difference whatsoever.
The designer will place the event subscriptions on the InitializeComponent method and you should not do any changes to that method because the designer might override them or crash if it's something it can't handle.
Usually, the event subscriptions are events the form subscribes from its children. When the from is closed/disposed, all the children are disposed and each child will dispose event subscriptions.
Problems arise when the form subscribes to outside components. Then the form becomes "attached" to those components and, if not unsubscribed, becomes a resource leak.
There's also the possibility of events being fired when the form is not ready to handle them.
I've used a mixed approach where events from child controls were subscribed in the designer (or carefully manually coded in the InitializeComponent method) and used the AttachEvents/DetachEvents approach for components outside the UI (or the scope of the form/control).
I have a program which allows the editing of product information. I noticed that it was not releasing memory after closing the editing forms. After some research I stumbled upon this question which mentions that the problem may be that it is hanging on to event subscriptions.
That made sense to me because this form has about 100+ controls on it, many of which are custom with custom events which are subscribed to by their parent controls. This creates a pretty large hierarchy of event subscriptions. So I looked for a way to release these and found this which allows you to unsubscribe from that event.
The problem is, I have a ton of subscriptions. Do I really have to manually unsubscribe from each event one by one on form close, or is there at least a way to release them in one fell swoop, or loop through them?
Remember this: The object on the LEFT of the += keeps alive the object containing the method on the RIGHT of the +=. That is, the object that raises the event keeps alive the object that handles the event, even if the object (such as a form) that handles the event is disposed.
So the thing you need to ensure is that all the event-raisers have gone away.
However, if all the event-raisers happen to be controls in the same Form class that subscribes to those events, you will not need to manually unhook all the event handlers when the form is closed.
This is because the controls that raise the events to which to form has subscribed have the same lifetime as the form itself.
You only need to worry if you subscribe to events raised by an object that has a longer lifetime than the object that is subscribing. Then the subscribing object (the form) would need to unsubscribe when it (the form) is disposed.
It depends on how long your form and its events will be living.
However, you can loop through your controls within the form, releasing the events.
If you remove a nonexisting event accidentally - don't worry, it won't throw an exception.
For example, this is how to get rid of all your TextBox.KeyDown-Events:
private void frm_FormClosed(object sender, FormClosedEventArgs e)
{
foreach (Control tb in this.Controls)
{
if (tb is TextBox)
{
TextBox tb1 = (TextBox)tb;
tb1.KeyDown -= TextBox_KeyDown;
}
}
So we know that if you attach an event handler, we should remove it at some point if the object is not being used anymore. How does this work for Window objects?
Take for example, the Window's Loaded event, or Closing event. If we register the EventHandlers to handle these events in the Initialize method, why don't we ever unregister them?
Because it is not a big deal. Usually you subscribe to the event in the derived class itself, so you will not cause the instance to linger in memory because of a stray event handler subscription. Also you will need the Closing event handler until the very end of the Window's lifetime, there is no point in unsubscribing from it.
Okay, make an example here:
I have UserControl A, UserControl B, UserControl C and one Windows Form.
This Windows Form is only started with UserControl A.
UserControl C has [Next] and [Back] buttons.
Say, UserControl A is declared with an event handler. One of function in UserControl A will actually raise the event call to execute one function at UserControl C.
So, at UserControl C, I have to add with
"UserControlA.OneFunction += this.UserControlC_Function;"
If I click Next button at UserControl C, it will dispose the UserControl A and add new UserControl B to the Windows Form. But I never remove this event handler manually.
One of the function in UserControl A is the caller (where event is declared).
One of the function in UserControl C is the listener.
So, these are my questions:
Should I manually remove the handler before UserControl A disposed?
Will this User Control A dispose automatically remove the handler that declared previously?
Should I add this somewhere?
"UserControlA.OneFunction -= this.UserControlC_Function;"
By convention, we don't. And since no event should be invoked after disposal, there is no need to do so unless the control in question is behaving weirdly.
No. At least there isn't such code as seen from reflector.
You don't need to remove the handlers in this case because neither the form nor its buttons are referenced by code external to the form, and the entire object graph will therefore be garbage collected.
The answer to this post does a really good job explaining when you need to manually remove an event handler and when it is not necessary.
Do I need to remove event subscriptions from objects before they are orphaned?
If the form is released (assuming no other objects has a reference to the objects in question) there's little risk of not removing the event handler, however it's a good idea always to remove the event handler before the object listening can no longer be reach (ie all variables referencing the object i sout of scope) not doing so can create a memory leak.
This is not the case in your situation (if I get what you are describing, code would make it more clear)
The problem would be if you attach a delegate referencing object C to an event on object A and then looses access to C (e.g. assigning a new value to the variable). C would then hang around until A is garbage collected
If the memory lifetime of an event publisher is not limited relative to the useful lifetime of an event subscriber, failure to unsubscribe an event will likely cause a memory leak. Were it not for the unfortunate hassle of doing so, there wouldn't be any reason for an event subscriber that was being disposed not to unsubscribe from all events, and for an event publisher that was being disposed not to nullify all event subscriptions. Since neither C# nor VB provides any convenient means of doing those things, however, one has to balance the hassle of proper subscription handling with the fact that in many situations one can get away skimping on it.
I just came to realize, by reading some questions and answers on StackOverflow, that adding event handlers using += in C# (or i guess, other .net languages) can cause common memory leaks...
I have used event handlers like this in the past many times, and never realized that they can cause, or have caused, memory leaks in my applications.
How does this work (meaning, why does this actually cause a memory leak) ?
How can I fix this problem ? Is using -= to the same event handler enough ?
Are there common design patterns or best practices for handling situations like this ?
Example : How am I supposed to handle an application that has many different threads, using many different event handlers to raise several events on the UI ?
Are there any good and simple ways to monitor this efficiently in an already built big application?
The cause is simple to explain: while an event handler is subscribed, the publisher of the event holds a reference to the subscriber via the event handler delegate (assuming the delegate is an instance method).
If the publisher lives longer than the subscriber, then it will keep the subscriber alive even when there are no other references to the subscriber.
If you unsubscribe from the event with an equal handler, then yes, that will remove the handler and the possible leak. However, in my experience this is rarely actually a problem - because typically I find that the publisher and subscriber have roughly equal lifetimes anyway.
It is a possible cause... but in my experience it's rather over-hyped. Your mileage may vary, of course... you just need to be careful.
I have explained this confusion in a blog at https://www.spicelogic.com/Blog/net-event-handler-memory-leak-16. I will try to summarize it here so that you can have a clear idea.
Reference means, "Need":
First of all, you need to understand that, if object A holds a reference to object B, then, it will mean, object A needs object B to function, right? So, the garbage collector won't collect object B as long as object A is alive in the memory.
+= Means, injecting reference of Right side object to the left object:
The confusion comes from the C# += operator. This operator does not clearly tell the developer that, the right-hand side of this operator is actually injecting a reference to the left-hand side object.
And by doing so, object A thinks, it needs object B, even though, from your perspective, object A should not care if object B lives or not. As object A thinks object B is needed, object A protects object B from the garbage collector as long as object A is alive. But, if you did not want that protection given to the event subscriber object, then, you can say, a memory leak occurred. To emphasize this statement, let me clarify that, in the .NET world, there is no concept of memory leak like a typical C++ unmanaged program. But, as I said, object A protects object B from garbage collection and if that was not your intention, then you can say a memory leak happened because object B was not supposed to be living in the memory.
You can avoid such a leak by detaching the event handler.
How to make a decision?
There are lots of events and event handlers in your whole code-base. Does it mean, you need to keep detaching event handlers everywhere? The answer is No. If you had to do so, your codebase will be really ugly with verbose.
You can rather follow a simple flow chart to determine if a detaching event handler is necessary or not.
Most of the time, you may find the event subscriber object is as important as the event publisher object and both are supposed to be living at the same time.
Example of a scenario where you do not need to worry
For example, a button click event of a window.
Here, the event publisher is the Button, and the event subscriber is the MainWindow. Applying that flow chart, ask a question, does the Main Window (event subscriber) supposed to be dead before the Button (event publisher)? Obviously No. Right? That won't even make sense. Then, why worry about detaching the click event handler?
An example when an event handler detachment is a MUST.
I will provide one example where the subscriber object is supposed to be dead before the publisher object. Say, your MainWindow publishes an event named "SomethingHappened" and you show a child window from the main window by a button click. The child window subscribes to that event of the main window.
And, the child window subscribes to an event of the Main Window.
From this code, we can clearly understand that there is a button in the Main Window. Clicking that button shows a Child Window. The child window listens to an event from the main window. After doing something, the user closes the child window.
Now, according to the flow chart I provided if you ask a question "Does the child window (event subscriber) supposed to be dead before the event publisher (main window)? The answer should be YES. Right? So, detach the event handler. I usually do that from the Unloaded event of the Window.
A rule of thumb: If your view (i.e. WPF, WinForm, UWP, Xamarin Form, etc.) subscribes to an event of a ViewModel, always remember to detach the event handler. Because a ViewModel usually lives longer than a view. So, if the ViewModel is not destroyed, any view that subscribed event of that ViewModel will stay in memory, which is not good.
Proof of the concept using a memory profiler.
It won't be much fun if we cannot validate the concept with a memory profiler. I have used JetBrain dotMemory profiler in this experiment.
First, I have run the MainWindow, which shows up like this:
Then, I took a memory snapshot. Then I clicked the button 3 times. Three child windows showed up. I have closed all of those child windows and clicked the Force GC button in the dotMemory profiler to ensure that the Garbage Collector is called. Then, I took another memory snapshot and compared it. Behold! our fear was true. The Child Window was not collected by the Garbage collector even after they were closed. Not only that but the leaked object count for the ChildWindow object is also shown as "3" (I clicked the button 3 times to show 3 child windows).
Ok, then, I detached the event handler as shown below.
Then, I have performed the same steps and checked the memory profiler. This time, wow! no more memory leak.
Yes, -= is enough, However, it could be quite hard to keep track of every event assigned, ever. (for detail, see Jon's post). Concerning design pattern, have a look at the weak event pattern.
An event is really a linked list of event handlers
When you do += new EventHandler on the event it doesn’t really matter if this particular function has been added as a listener before, it will get added once per +=.
When the event is raised it go through the linked list, item by item and call all the methods (event handlers) added to this list, this is why the event handlers are still called even when the pages are no longer running as long as they are alive (rooted), and they will be alive as long as they are hooked up. So they will get called until the eventhandler is unhooked with a -= new EventHandler.
See Here
and MSDN HERE
I can tell you that this might possibly become an issue in Blazor. You can have a Component subscribing to events using the += syntax and in the long run, this will cause leaks.
The only solution to this (that I'm aware of) is to not use anonymous methods, have the Component inherit from IDisposable and use Dispose() to unsubscribe the event handler.