Coder Perfect

Why are memory leaks in Event Handlers so common, and how can you avoid them?

Problem

By reading various queries and answers on StackOverflow, I’ve discovered that adding event handlers using += in C# (or, I assume, other.net languages) might result in memory leaks…

I’ve used event handlers like this a lot in the past and never knew they could (or did) cause memory leaks in my applications.

What is the mechanism behind this (i.e., why does it produce a memory leak)? What can I do to resolve this issue? Is it sufficient to apply -= to the same event handler? Are there any established design patterns or best practices for dealing with circumstances like this? For example, how am I going to handle an application with many threads that use several event handlers to trigger multiple UI events?

Is there a decent and straightforward approach to monitor this in a large application that has already been built?

Asked by gillyb

Solution #1

The reason for this is simple: when an event handler is subscribed, the event publisher maintains a reference to the subscriber via the event handler delegate (assuming the delegate is an instance method).

If the publisher outlives the subscriber, the subscriber will be kept alive even if no other references to the subscriber exist.

Yes, if you unsubscribe from the event with an equal handler, the handler and the potential leak will be removed. However, in my experience, this is rarely a problem because, in most cases, the publisher and subscriber have about identical lifespans.

It’s a probable cause… but it’s been over-hyped in my experience. Of course, your results may differ; all you have to do is be cautious.

Answered by Jon Skeet

Solution #2

In a blog post at https://www.spicelogic.com/Blog/net-event-handler-memory-leak-16, I clarify the confusion. I’ll attempt to summarize it here so you can have a good picture of what’s going on.

Reference means, “Need”:

First and foremost, you must grasp that if object A has a reference to object B, it follows that object A requires object B to function, correct? As a result, as long as object A is active in the memory, the garbage collector will not collect object B.

+= Injecting a reference to a right-side object into a left-side object:

The += operator in C# is the source of the misunderstanding. The right-hand side of this operator does not explicitly indicate to the developer that it is actually injecting a reference to the left-hand side object.

And, as a result, object A believes it need object B, even though, from your perspective, object A should not be concerned with whether or not object B lives. Object A protects object B from the garbage collector as long as object A is alive because it believes object B is essential. However, if you did not want the event subscriber object to be protected, you might assert that a memory leak occurred. To underline this point, let me state that, unlike a conventional C++ unmanaged program, there is no concept of memory leak in the.NET environment. However, as I previously stated, object A protects object B from trash collection, and if this was not your purpose, you can claim a memory leak.

Detaching the event handler will prevent such a leak.

What is the best method for making a choice?

In your entire code base, there are several events and event handlers. Does this imply that you must keep removing event handlers at all times? No, that is not the case. If you were forced to do so, your codebase would be extremely verbose.

You can use a basic flow chart to determine whether or not a detaching event handler is required.

The event subscriber object is usually just as important as the event publisher object, and both are expected to be alive at the same time.

An example of a situation in which you do not need to be concerned

For instance, a window’s button click event.

The Button is the event publisher, and the MainWindow is the event subscriber in this case. Asking a question based on that flow chart, is the Main Window (event subscriber) expected to be dead before the Button (event publisher)? Clearly, no. Right? That isn’t going to make any sense. Why should you be concerned about disconnecting the click event handler?

When event handler separation is required, as in this case.

I’ll give an example in which the subscriber object should die before the publisher object. Let’s say your MainWindow fires an event called “SomethingHappened,” and you use a button click to reveal a child window from the main window. The main window’s event is subscribed to by the child window.

In addition, the child window is subscribed to one of the Main Window’s events.

We can see that there is a button in the Main Window based on this code. When you click that button, a Child Window appears. The main window sends an event to the child window, which the child window listens to. The user closes the child window after completing a task.

Now, if you ask, “Does the child window (event subscriber) required to be dead before the event publisher (primary window)?” according to the flow chart I supplied, the answer is yes. Yes should be the answer. Right? Detach the event handler as a result. I normally do this from the Window’s Unloaded event.

Always remember to detach the event handler if your view (WPF, WinForm, UWP, Xamarin Form, etc.) subscribes to an event of a ViewModel. Because a ViewModel typically outlasts a view. As a result, if the ViewModel is not destroyed, any views that subscribed to its events will remain in memory, which is undesirable.

A RAM profiler was used to demonstrate the notion.

It won’t be much fun if we can’t use a memory profiler to verify the concept. In this experiment, I used JetBrain dotMemory profiler.

First, I’ve launched the MainWindow, which appears as follows:

Then I snapped a memory photograph. After that, I pressed the button three times. There were three child windows that appeared. To ensure that the Garbage Collector is called, I closed all of those child windows and used the Force GC button in the dotMemory profiler. Then I compared it to another memory snapshot. Our apprehensions were confirmed. Even after they were closed, the garbage collector did not gather the garbage from the Child Window. Not only that, but the ChildWindow object’s leaked object count is likewise “3.” (I clicked the button 3 times to show 3 child windows).

So, as indicated below, I disconnect the event handler.

After that, I repeated the procedures and ran the RAM profiler. Wow, wow, wow, wow, wow, wow, wow There will be no more memory leaks.

Answered by Emran Hussain

Solution #3

Yes, -= suffices; nevertheless, it may be difficult to maintain track of every event assigned at all times. (For further information, check Jon’s post). Take a look at the weak event pattern if you’re looking for a design pattern.

Answered by Femaref

Solution #4

An event is actually a collection of event handlers linked together.

It doesn’t matter if this function has been added as a listener before when you do += new EventHandler on the event; it will be added once every +=.

When an event is produced, it goes through the linked list item by item and calls all of the methods (event handlers) assigned to it; this is why event handlers are still called even if the pages are no longer running as long as they are alive (rooted), which they will remain as long as they are connected. As a result, they’ll continue to be called until the eventhandler is unhooked with a -= new EventHandler.

See Here

and MSDN HERE

Answered by TalentTuner

Solution #5

I can tell you that in Blazor, this might become a problem. You can have a Component subscribe to events using the += syntax, but this will lead to leaks in the long term.

The only approach I’m aware of is to avoid using anonymous methods and instead have the Component inherit from IDisposable, then use Dispose() to unsubscribe the event handler.

Answered by David Guida

Post is based on https://stackoverflow.com/questions/4526829/why-and-how-to-avoid-event-handler-memory-leaks