i recently created a sample application, wherein i implemented the events and delegates, when the Properties value is changed this event will raise, i have a question regarding events
Does event objects are created in memory? or they are just static object which gets removed once the event is fired?
Is it necessary to remove the handler once the event is executed, to free-up resources. does removing handler once done, boost's up the application performance, i am talking about the application which are using lots of events
Events do take memory and are not garbage collected until after you unsubscribe from them. They are a common cause of memory leaks.
Events can be both static and instance bound. Subscribers to the event are never removed while the event broadcaster is alive, unless implicitly done so, usually with the -= operator.
Yes, yes and yes. If you don't clean-up your subscribers you have a memory-leak waiting to happen.
If all this is a concern to you perhaps you could look into the WeakEvent pattern.
events are like delegates ( with another layer of protection) .
when you register to an event - you are actually making a reference to another object.
this object can't go through GC because you made a reference to it !
it isnt "un-referenced".
but your object CAN go through GC. ( if un-referenced).
so you end up with memory leak.
you should manually remove the reference .
Related
I have a class (Model) an object of which serves as a blueprint for (short-lived) objects of another class (ModeledRelation). Model defines an event ModeledRelation always subscribes to in order to be notified when Model changes, so ModeledRelation objects can reflect these changes 1:1.
Now ModeledRelation objects are used somewhere else for some time and then finally go out of scope. But because the event still holds a reference to them they prevent garbage collection.
Of course I formally want the objects to be GC'ed already if the event is the only reference left. I know I can unsubscribe from the event in ModeledRelation.Dispose but that would require explicitely calling Dispose and this feels a little too crafty for a purely managed class. I also want to be safe in the case that the ModeledRelation object silently slips out of scope and not have a memory leak then.
Maybe I am thinking in a totally wrong direction and this has to be done differently.
You should look at the Weak Event Patterns :
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/weak-event-patterns
Upon meditating about the problem throughout the day I have recognized what is the core issue about my approach: subscribing to the event during construction of ModeledRelation. This leads to the natural conclusion that unsubscription has to be done during object destruction... which never happens because event still points to the object and GC is blocked.
Instead the right solution to the problem is to subscribe to the event when the ModeledRelation is actually used (in my case added to another object's collection). Because then the natural moment to unsubscribe is when it ceases to be used (if it is removed from the collection of the other object). If it is reused afterwards it will resubscribe, whereas if it slips out of scope it will just be GC'ed because no events point to it anymore!
I have the following code to let the GUI respond to a change in the collection.
myObservableCollection.CollectionChanged += ((sender, e) => UpdateMyUI());
First of all is this a good way to do this?
Second: what's the code to unsubscribe from this event? Is it the same but with -= (and then the complete anonymous method again)?
First of all... yes its a good way of doing it, it's clean, small form and easy to read & understand... the caveat of course is "Unless you later want to unsubscribe".
I believe Jon Skeet pointed out before that
"the specification explicitly doesn't guarantee the behaviour either way when it comes to equivalence of delegates created with anonymous methods."
So if you need to unsubscribe from the event at a later time, you'd be best to actually create a delegate instance so you can hang onto the reference for later.
var myDelegate = delegate(sender, e){UpdateMyUI()};
myObservableCollection.CollectionChanged += myDelegate;
myObservableCollection.CollectionChanged -= myDelegate;
If you need to unsubscribe from an event, you need an instanced reference. Unfortunately, that means you can't use that particular syntax.
It's an ok way to go, unless myObservableCollection is going to live longer than 'this', in which case you could end up with a memory leak, as the delegate which is created behind the scenes will conserve a reference to your 'this', which will keep it alive. If you are repeatedly creating and 'destroying' whatever is listening to the event, you will find that they aren't being collected by the garbage collector.
If this is a problem, you can go the route suggested in the answers, conserving a reference to the handler, which you must create first.
Another solution is to use weak references to create an event handler which will allow the subscriber to be collected if there are not other references. I've explored this solution in this question and answer.
Say I have the following code:
public event EventHandler DatabaseInitialized = delegate {};
//a intederminant amount of subscribers have subscribed to this event...
// sometime later fire the event, then create a new event handler...
DatabaseInitialized(null,EventArgs.Empty);
//THIS LINE IS IN QUESTION
DatabaseInitialized = delegate {};
Will this clear out the subscribers, replacing it with new empty default? And, will the event notify all subscribers before they get cleared out? I.E. Is there a chance for a race condition?
Yes it will clear it out. And because events fire syncronously in the same thread there shouldn't be race condition.
My advice: when in doubt, write a small test application and... well, test it.
UPDATE: I tested it before posting. (In response to minuses.)
To unsubscribe from the event use event-=delegate, so you're sure that resource is free. Even if by official Microsoft documentation it's not necessary, in my own experience, especially on a large scale complex project, unnecessary events suscribers are source for memory leaks. So unsubscribe from them explicitly.
I have the following code to let the GUI respond to a change in the collection.
myObservableCollection.CollectionChanged += ((sender, e) => UpdateMyUI());
First of all is this a good way to do this?
Second: what's the code to unsubscribe from this event? Is it the same but with -= (and then the complete anonymous method again)?
First of all... yes its a good way of doing it, it's clean, small form and easy to read & understand... the caveat of course is "Unless you later want to unsubscribe".
I believe Jon Skeet pointed out before that
"the specification explicitly doesn't guarantee the behaviour either way when it comes to equivalence of delegates created with anonymous methods."
So if you need to unsubscribe from the event at a later time, you'd be best to actually create a delegate instance so you can hang onto the reference for later.
var myDelegate = delegate(sender, e){UpdateMyUI()};
myObservableCollection.CollectionChanged += myDelegate;
myObservableCollection.CollectionChanged -= myDelegate;
If you need to unsubscribe from an event, you need an instanced reference. Unfortunately, that means you can't use that particular syntax.
It's an ok way to go, unless myObservableCollection is going to live longer than 'this', in which case you could end up with a memory leak, as the delegate which is created behind the scenes will conserve a reference to your 'this', which will keep it alive. If you are repeatedly creating and 'destroying' whatever is listening to the event, you will find that they aren't being collected by the garbage collector.
If this is a problem, you can go the route suggested in the answers, conserving a reference to the handler, which you must create first.
Another solution is to use weak references to create an event handler which will allow the subscriber to be collected if there are not other references. I've explored this solution in this question and answer.
I'm not sure if I'm entirely clear on the implications of attaching to events in objects.
This is my current understanding, correct or elaborate:
1. Attaching to local class events do not need to be detached
Examples:
this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
public event EventHandler OnMyCustomEvent = delegate { };
I'm assuming that when your object is disposed or garbage collected, the functions are deallocated and would automatically detach from the events.
2. Attaching to objects you no longer need (= null;) have to be detached from
Examples:
Attaching to a timer's Elapsed event, which you only respond to once. I would assume you need to store the Timer in a local variable so you can detached the Elapsed event after the event fires. Thus, declaring the timer in a local method scope like so would result in a leak:
System.Timers.Timer myDataTimer = new System.Timers.Timer(1000);
myDataTimer.Elapsed += new System.Timers.ElapsedEventHandler(myDataTimer_Elapsed);
3. Attaching to events in a local object to your class does not require disposing?
For example, if you had an ObservableCollection that your creates, monitors, and lets die. If you attached to the CollectionChanged event using a local, private function, wouldn't this function deallocate when your class is garbage collected, causing the ObservableCollection to also be freed?
I'm sure I have places where I've stopped using objects and have failed to detach from an event (for example, the timer example I made), so I'm looking for a clearer explanation on how this works.
I think you're making it more complicated than it needs to be. You just need to remember two things:
When you subscribe to an event, the event's "owner" (the publisher) generally keeps a reference to the delegate you subscribe with.
If you use an instance method as the action of a delegate, then the delegate has a reference to its "target" object.
This means that if you write:
publisher.SomeEvent += subscriber.SomeMethod;
Then subscriber won't be eligible for garbage collection before publisher is unless you unsubscribe later.
Note that in many cases, subscriber is just this:
publisher.SomeEvent += myDataTimer_Elapsed;
is equivalent to:
publisher.SomeEvent += this.myDataTimer_Elapsed;
assuming it's an instance method.
There is no reverse relationship just due to event subscription - in other words the subscriber doesn't keep the publisher alive.
See my article on events and delegates for more information, by the way.
The remaining references preventing garbage collection has one more effect that may be obvious but nontheless not yet stated in this thread; the attached event handler will be excuted as well.
I have experienced this a couple of times. One was when we had an application that gradually became slower and slower the longer it run. The application created the user interface in a dynamic fashion by loading user controls. The container made the user controls subscribe to certain events in the environment, and one of these were not unsubscribed from when the controls were "unloaded".
After a while this led to a large number of event listeners being executed each time that particular event was raised. This can of course lead to serious race conditions when a good number of "sleeping" instances suddenly wake up and try to act on the same input.
In short; if you write code to hook up an event listener; make sure that you release as soon as it's not needed any longer. I almost dare to promise it will save you from at least one headache at some point in the future.
The relevant case where you have to unsubscribe from an event is like this:
public class A
{
// ...
public event EventHandler SomethingHappened;
}
public class B
{
private void DoSomething() { /* ... */ } // instance method
private void Attach(A obj)
{
obj.SomethingHappened += DoSomething();
}
}
In this scenario, when you dispose of a B, there will still be a dangling reference to it from obj's event handler. If you want to reclaim the B's memory, then you need to detach B.DoSomething() from the relevant event handler first.
You could run into the same thing if the event subscription line looked like this, of course:
obj.SomethingHappened += someOtherObject.Whatever.DoSomething();
Now it's someOtherObject that's on the hook and can't be garbage collected.