This question already has answers here:
Is it bad to not unregister event handlers?
(2 answers)
Closed 9 years ago.
I have 3 questions concerning events:
Should I always unsubscribe events that were subscribed?
What happens if I do NOT?
In the below examples, how would you unsubscribe from the subscribed events?
I have for example this code:
Ctor: Purpose: For database property updates
this.PropertyChanged += (o, e) =>
{
switch (e.PropertyName)
{
case "FirstName": break;
case "LastName": break;
}
};
and this: Purpose: For GUI-binding wrap the model into viewmodels
ObservableCollection<Period> periods = _lpRepo.GetDailyLessonPlanner(data.DailyDate);
PeriodListViewModel = new ObservableCollection<PeriodViewModel>();
foreach (Period period in periods)
{
PeriodViewModel periodViewModel = new PeriodViewModel(period,_lpRepo);
foreach (DocumentListViewModel documentListViewModel in periodViewModel.DocumentViewModelList)
{
documentListViewModel.DeleteDocumentDelegate += new Action<List<Document>>(OnDeleteDocument);
documentListViewModel.AddDocumentDelegate += new Action(OnAddDocument);
documentListViewModel.OpenDocumentDelegate += new Action<int, string>(OnOpenDocument);
}
PeriodListViewModel.Add(periodViewModel);
}
Well, let's take the last question first. You can't reliably unsubscribe from an event that you've subscribed to directly with a lambda expression. You either need to keep a variable around with the delegate in (so you can still use a lambda expression) or you need to use a method group conversion instead.
Now as for whether you actually need to unsubscribe, it depends on the relationship between the event producer and the event consumer. If the event producer should live for longer than the event consumer, you should unsubscribe - because otherwise the producer will have a reference to the consumer, keeping it alive for longer than it should be. The event handler will also keep getting called for as long as the producer produces it.
Now in many cases that's not a problem - for example, in a form the button that raises the Click event is likely to live for about as long as the form on which it's created, where the handler is typically subscribed... so there's no need to unsubscribe. This is very typical for a GUI.
Likewise if you create a WebClient solely for the purpose of a single asynchronous request, subscribe to the relevant event and start the asynchronous request, then the WebClient itself will be eligible for garbage collection when the request has finished (assuming you don't keep a reference elsewhere).
Basically, you should always consider the relationship between the producer and the consumer. If the producer is going to live longer than you want the consumer to, or it's going to continue raising the event after you're no longer interested in it, then you should unsubscribe.
1) It depends. Usually it's a good idea, but there are typical cases where you don't need to. Basically, if you are sure that the subscribing object is going to outlive the event source, you ought to unsubscribe, otherwise this would create an unnecessary reference.
If however your object is subscribing to its own events, like in the following:
<Window Loaded="self_Loaded" ...>...</Window>
--then you don't have to.
2) Subscribing to an event makes additional reference to the subscribing object. So if you don't unsubscribe, your object might be kept alive by this reference, making effectively a memory leak. By unsubscribing you are removing that reference. Note that in the case of self-subscription the problem doesn't arise.
3) You can do like that:
this.PropertyChanged += PropertyChangedHandler;
...
this.PropertyChanged -= PropertyChangedHandler;
where
void PropertyChangedHandler(object o, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "FirstName": break;
case "LastName": break;
}
}
You don't have to desubscribe from an event when the instance that is subscribing has the same scope as the instance that is being subscribed to.
Lets say you are a form and you are subscribing to a control, these two together form a group. However, if you have a central class that manages forms and you have subscribed to the Closed event of that form, these do not form a group together and you must desubscribe once the form is closed.
Subscribing to an event makes the subscribed instance create a reference to the instance being subscribed to. This prevents garbage collection. So, when you have a central class that manages form instances, this will keep all forms in memory.
WPF is an exception because it has a weak event model where events are subscribed to using weak references and it will not hold the form in memory. However, it is still best practice to desubscribe when you are not part of the form.
You may take a look at this article on MSDN. Quote:
To prevent your event handler from
being invoked when the event is
raised, simply unsubscribe from the
event. In order to prevent resource
leaks, it is important to 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, your
subscriber object will not be garbage
collected.
1.) Should I always desubscribe events that were subscribed?
Usually yes. The only exception is when the object on which you subscribed isn't referenced anymore and will be garbage collected soon.
2.) What happens if I do NOT?
The object on which you subscribed will hold a reference to the delegate, which in turn holds a reference to its this pointer, and thus you'll get a memory leak.
Or if the handler was a lamda it will hold onto whatever local variables it bound, which thus won't be collected either.
Related
I'm trying to understand how a Control events are unsubscribed. Suppose I have a textbox and I have subscribed the TextChanged event using the WinForms designer.
Is the TextChanged event automatically unsubscribed in the Textbox destructor, or must I explicitly unsunscribe to avoid memory leaks?
public void InitializeComponents()
{
...
this.emailTextBox.TextChanged += emailTextBox_TextChanged;
...
}
public override void Dispose()
{
if( disposing )
{
// DO I REALLY NEED THIS LINE?
this.emailTextBox.TextChanged -= emailTextBox_TextChanged;
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
Any object which subscribes to events from a longer-lived object should implement IDisposable and should unsubscribe those events when it is Disposed. Conceptually, there's no reason why objects shouldn't unsubscribe from all events when they are disposed, since doing so would avoid problems if an object whose events one subscribed turned out to live longer than expected. Unfortunately, the event architecture in .NET provides no mechanism for conveniently ensuring that events get cleaned up when objects are disposed, and having code unsubscribe a bunch of events when an object is disposed may make it harder to make sure that the few events which really need to be cleaned up are among the ones that are.
In this situation I beleive it is OK not to unsubscribe because the TextBox to which you're subscribing is wholly contained within the parent control (or that's what I'm assuming.)
Therefore when no further references to the parent control exist, there won't be any external references to the TextBox and so both objects will become eligible for GC.
There are situations when you should unsubscribe from events to prevent memory leaks because the reference held by the event (in it's list of subscribers) is just the same as any other reference and would prevent the subscriber from being GC'd.
Such situations can occur when an object subscribes to an event on an external object (i.e. not owned by this object.) In this situation the subscriber would only become eligible for GC after the subscribed-to object was eligible for GC.
The events are actually a list of event handlers (function delegates). So when you write this:
this.emailTextBox.TextChanged += emailTextBox_TextChanged;
You actually add your delegate emailTextBox_TextChanged to the list of existing delegates associated to the TextChanged event.
What this means is that when the textbox is disposed, this list will be disposed too, so you don't need to unsubscribe events in that case, and you won't have memory leaks.
So to answer your question, the event isn't really unsubscribed in the textbox destructor, but you don't need to do it explicitly.
The only case in which it will be useful to unsubscribe is when you don't want your function to handle the event anymore during execution, but I think I've never actually needed to do that.
Yes, you better unsubscribe. As official docs say (here)
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.
Whenever you add a delegate to an event handler, you should remove it later, right? So if you attach an anonymous method to an event, does this create an event handler leak since you can't later remove it? This code sample from http://msdn.microsoft.com/en-us/library/0yw3tz5k%28VS.80%29.aspx seems to imply that this an okay practice though.
// Create a handler for a click event
button1.Click += delegate(System.Object o, System.EventArgs e)
{ System.Windows.Forms.MessageBox.Show("Click!"); };
Is this really an okay practice?
Whenever you add a delegate to an event handler, you should remove it later, right?
Not necessarily, no. Often you want the event handler to stay valid for as long as the event itself can be raised - that's certainly very common with UIs.
Is this really an okay practice?
Absolutely, so long as you don't need to unhook the handler. Think about the point at which you'd unhook the event handler. If it's "when the form (or button, or whatever) is elegible for garbage collection" then what benefit is there in removing the handler? Just let it be garbage collected with the form...
Whenever you add a delegate to an event handler, you should remove it later, right?
Well, not always. There are two reasons why you'd want to remove an event handler that you're adding:
You're constantly adding handlers to the same instance that are short lived. If you didn't remove them then there would be more and more handlers added, when most of them aren't needed.
Your handler internally holds onto a reference to an object who's lifetime is much shorter than the lifetime of whatever object the event belongs to, and the event handler won't be (or can't be) called once that other object goes out of scope. Leaving the event handler attached will either force it to stay in memory longer than desired, or possibly result in using an object that's "stale" and shouldn't be used anymore. (For example, if the resource has already been disposed you don't want that event to fire anymore.)
The reason #2 is an issue is because of how Garbage Collection works in C#. It marks all objects that it can be 100% sure are in scope as "alive", and then follows everything that any of those "alive" objects reference as also being "alive" until it's followed every reference in every live object. Anything that was never marked as "alive" is then deemded "dead" and eligible for garbage collection.
When you have an event handler attached to an event that delegate contains two things, an instance of an object and a method to run on that object. That referenced object won't be able to be garbage collected until either:
The object with the event is no longer "alive".
You remove the event handler (i.e. the reference to) your delegate, allowing your object to be freed earlier.
That said, a significant percentage of cases don't apply to either of those, so there's no need to bother removing the event handlers.
As an example, I often see people removing event handlers just before the event object goes out of scope. That's pointless. If the object is out of scope there's no problem with it holding onto references to...whatever.
Now, if you are in one of those few situations in which you do need to unsubscribe the event handler, and you're using an anonymous method you need to...not. Just create a class that can make it a named method and use that.
Subscibing to event with anonymous method (or lambda expression) potentially can lead to memory leaks, but not in this case.
In this case compiler will generate an anonymous method inside current class and you don't have any memory related issues as long as your button will not live much longer than your object.
The use of inline anonymous delegates as event handlers does prevent those handlers being removed, as you stated. This can indeed cause problems, especially if the delegate comes from a different object. If you had a class A with a public event E, and E was subscribed to by a class B (that has no containing/contains relationship to A) attaching an anonymous handler H, H is technically a member of B, and so as long as it's referred to (by being attached to A's event), B won't be GCed. B's lifetime becomes tied to A's, and if you didn't want or expect that you now have a memory leak.
Now, that's not always a problem. If B contains A, or the other way around, then A and B's lifetimes are already tied together anyway; in your case, the button itself will very probably be disposed of before its containing control that attached the handler. Similarly, A and B could be long-lived objects (say, the program's main form and a data repository) and won't be GCed until the program terminates anyway. As long as you never have to care about a difference in lifetime between A and B, and you never need to detach H from E to stop exhibiting whatever behavior H has, then you can attach all the anonymous handlers you like.
I have a rather short question about anonymous event handlers:
This is the code that I have:
public void AddTestControl(Control ctrl)
{
ctrl.Disposed += (o, e) => { RemoveTestControl(ctrl); };
ctrl.SomeEvent += _Control_SomeEvent;
}
public void RemoveTestControl(Control ctrl)
{
ctrl.SomeEvent -= _Control_SomeEvent;
}
Is this code above fine, or should the code be rewritten in order to remove the Disposed Event Handler?
Something like this:
public void AddTestControl(Control ctrl)
{
ctrl.Disposed += _Control_Disposed;
ctrl.SomeEvent += _Control_SomeEvent;
}
public void RemoveTestControl(Control ctrl)
{
ctrl.Disposed -= _Control_Disposed;
ctrl.SomeEvent -= _Control_SomeEvent;
}
Generally, the only situation where you need to remove the event handlers from an object in order for it to be eligible for garbage collection is when the publisher object (the one defining the event) lives longer than the subscriber object (the one containing the event handlers). In such a situation the GC won't be able to release the subscriber when it goes out of scope since it's still being referenced by the publisher.
In this case, assuming this is WebForms or WinForms, the publisher (that is the Control object), is most likely a child object of the subscriber (probably a Page or a Form), which will be the first to go out of scope taking all its associated objects with it. Hence there's no need to remove the event handlers.
It always feels cleaner to me to unsubscribe from events, even in situations where I know the subscribers always outlive the publisher (the object raising the event): the event will never be raised again, the publisher is no longer reachable and can be collected.
Then again, how many people go to the trouble of unsubscribing every event handler in e.g. a WinForms application? The object references point from the publisher to the subscribers, not the other way around, so the publisher can be collected while the subscribers live on. It doesn't present the same danger as the opposite situation, where a long-lived publisher (e.g. a static event) can wastefully keep potentially large subscribers alive long after they could have been collected.
If you want/need to unsubscribe, then the requirement to unsubscribe the same delegate makes anonymous event handlers a bit of a pain. The Reactive Extensions solve this problem in a neat way: rather than having to remember the delegate you subscribed, subscribing returns an IDisposable which unsubscribes when disposed. Chucking all your subscriptions into a CompositeDisposable lets you unsubscribe everything with just one Dispose call.
Both codez are fine, but I like second as a matter of personal preference. It reads clearer than the first.
On top of it with the first code, there's anonymous lambda delegate and it gets a current reference to ctrl. That code may behave unexpectedly depending on situation and compile optimisation settings: whether or not the call is inlined or not.
Not to mention that there's architectural problem with the code: you have ControlOwner and a bunch of Child Controls. I take it you're adding child controls to ControlOwner at runtime, and then trying to react to their behavivour by subscribing ControlOwner to the childControl events. This is fine for events like _ButtonClicked etc. But not good for Dispose. Let the child control handle it's disposing on itself, the OwnerControl doesn't need to know about it. Not to mention that it may not exist at a time ChildControl[n].Dispose is called.
In short:
* it is better to leave dispose event on ChildControl alone and do all clean up in ChildControl.Dispose
* it is not necessary to unsubscribe from events. Event dispatcher will check if subscriber is alive.
Say I've got an object that exists for the duration of an application. Let's call it GlobalWorker. GlobalWorker has events e.g. UserLoggedIn to which other objects can subscribe. Now imagine I've got a Silverlight page or an asp.net page or something, that subscribes to the UserLoggedIn event when it is constructed.
public SomePage()
{
GlobalWorker.Instance.UserLoggedIn += new EventHandler(OnUserLoggedIn);
}
private void OnLoggedIn(object sender, EventArgs e)
{
}
Does the existence of this event prevent the page from being garbage collected? If so, what's the best pattern to use in this instance: weak event-handlers, move the subscription to the Load event and unsubscribe in the UnLoad event?
Use Weak Events.
This is a common problem in WPF and it is good you have thought about it.
Yes the behavior prevents the page from being GC.
The reason being is that UserLoggedIn will hold a reference to SomePage indefinitely. There is no explicit removal of the handler and since weak events are not being used it will not implicitly get removed either.
You can use weak events as another poster stated, you can also re-think your design to some degree and see if you can functionalize or encapsulate the eventing behavior. Perhaps the data is all that needs to be global in this instance (user credentials), where as the event can be kept isolated.
You could also de-register in the handler itself if this was a one-off event you cared about. It really boils down to your specific need and instance, weak event pattern is the pattern to deal with this application wide but does not mean you have to use that pattern in each and every instance this problem surfaces.
I'm fixing a User control component using the .NET 1.1 framework.
There are many instances of this user control referencing a singleton wrapping a COM resource.
They subscribe to events from this resource.
I suspect that the reason why we are having a degrading performance is because the singleton is maintaining a reference to the user control classes even after their respective windows are gone. Thus preventing GC.
They unsubscribe the event in their finalize method.
Hence I suspect a chicken and egg problem. The finalize wont execute because they are being referenced through their event subscription in the longer lived Singleton, preventing GC.
Where in a User Control should I perform the event unsubscribe to make it eligible for GC?
I do not own the application hosting the user control.
You should unsubscribe when the control is disposed, really. If you can't easily modify the Dispose method yourself, you could add an event handler to the Disposed event:
ComSingleton.Foo += FooHandler;
this.Disposed += delegate { ComSingleton.Foo -= FooHandler; };
If you want to subscribe to events using anonymous methods or lambda expressions, you'll need to use a separate local variable so that you can refer to it again:
EventHandler tmp = delegate { Console.WriteLine("Something happened"); };
ComSingleton.Foo += tmp;
this.Disposed += delegate { ComSingleton.Foo -= tmp; };
An alternative is to use "weak event handlers" - there are many articles about this on the web; here's one which goes into a fair amount of detail.