How to keep event subscriptions from blocking garbage collection - c#

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!

Related

Can an event's publisher unsubscribe its listeners?

In my last question, I asked what would break a self-cleaning block of code designed to remove all subscriptions from an event's delegates field when the event's parent object is disposed. However, I was informed that setting the event to null does exactly what I was trying to do with the code in question, but without the extra cycles and lines of code.
This article demonstrates that setting an event to null (clearing the delegate field) does not guarantee that nothing is listening for it, and that even if the event is set to null, it may still be kept from the garbage collector.
So the question is, is there a way for the publisher to unsubscribe its listeners?
--
For context, I am aware that the listener is normally expected to remove its own subscription when it is done listening, but I would like a little bit more certainty than that, if possible. Also, I occasionally have to deal with code where I'm not entirely sure if all listeners have unsubscribed when the publisher is disposed.
In case it's relevant, the code from my last question is as follows:
public event CustomEventHandler customHandler;
...
///During this object's lifetime, some other object subscribes to this event.
...
///Method used for cleanup
void ClearSubscriptions(CustomEventHandler handler){
if(handler == null){return;}
Delegate[] delegates = handler.GetInvocationList();
foreach(Delegate item in delegates){
handler -= (CustomEventHandler)item;
}
}
This clears the event's delegates list, but I've been told that just setting customHandler = null should do the same. I also thought that this would ensure that nothing was still listening/referencing the event, but that does not seem to be the case, as is explained below.
To summarize the relevant code in the referenced article, the article's example is a form that allows the user to generate an "EventGenerator" object under one of three different conditions:
1.) There is no cleanup on the object's events.
2.) The publisher cleans up by setting the event to null.
3.) The listener cleans up by unsubscribing from the event.
These are controlled by a radio check, so only one condition may be active at a time. The EventGenerator object has an event that is fired when it is created. Each EventGenerator is assigned a number, starting at 0 and incrementing. The form has an event handler that subscribes to this event, and whenever that event is fired, the event handler prints that a new EventGenerator has been created, along with that object's number. Additionally, the form only references one EventGenerator at a time, so whenever a new one is created, the previous one is forgotten.
Under option 1, every time a new one of these objects is created, all objects that have been created fire off an "I've been created" dialog. This is expected since the form is still subscribed to all of these instances, even if they have been dereferenced.
Under option 3, when a new object is created, the form unsubscribes from the previous EventGenerator's event before dereferencing it, so the new object's "created" dialog displays, as well as the old object's "finalized" dialog. This demonstrates that the object has been gathered by the garbage collector and no longer holds any resources.
Option 2 is what confuses me. When option 2 is active, if a new EventGenerator is created, then the old one is disposed. The form does not unsubscribe, but the previous object does set its event to null. The "New Object" dialog is displayed once, with the new object's number. The previous generators are silent, meaning their events aren't being fired, and that is good. However, their "finalized" dialog never fires. This means that, even though the event has been set to null, the EventGenerator is still not eligible for garbage collection, creating a memory leak.
It seems to me that this is probably because the form itself never unsubscribes from the event under option 2. Then, even though the event doesn't really exist anymore, the form is still pointing at it, and that keeps the garbage collector away.
So with that context, I am curious. Is there a way for an event's publisher to unsubscribe its listeners and let Option 2 free up those dereferenced objects?
Also, sorry for this extra information being so verbose!

Do I have to remove eventHandlers in a finalizer?

I have a model class that has a Saved event. The idea is that if two viewmodels use that model object, if one of them changes it, the other will be updated.
Do I have to remove the event handler when I am no longer using its view model? Here is my code:
protected AbstractEntityViewModel(AbstractEntity ae)
{
this.ae = ae;
ae.Saved += delegate(object o, EventArgs e)
{
base.OnPropertyChanged(null);
};
}
Is this ok, or do I need to change this so that I can -= get rid of the delegate when the viewmodel is no longer used?
Direction of event References
To know whether you really need to detach the event handler, you've first got to understand that:
ae.Saved += delegate(object o, EventArgs e)
{
base.OnPropertyChanged(null);
};
means ae is now referencing this. So the object with the event is referencing the object with the event handler. It's not the other way around (event handler referencing event).
Objects not referenced by GC root can be collected
Furthermore, while ideally objects to be garbage collected are not referenced by any other objects, that is not strictly necessary:
The garbage collector can collect all objects which are not referenced by a GC root in any way (path). This means if you've got an insular graph of objects (objects referencing other objects of the graph, but there is no object outside the graph which is referencing an object inside the graph [no GC root either]), then the entire object graph will eventually be garbage collected. The more intertwined the graph is, the more expensive it is for the GC to collect it. Detaching event handlers helps in dissolving such graphs more speedily.
Correctly cleaning up objects
.Net does not feature Destructors. Instead there is the IDisposable pattern and finalizers (see Implementing Finalize and Dispose to Clean Up Unmanaged Resources).
Long story short:
Finalization methods (~Foo () { } for class Foo) are needed when an object manages unmanaged resources. They are called by the garbage collector when the GC is collecting the object. So the exact moment is not up to you.
Disposable pattern can be used to clean-up managed as well as unmanaged resources. If the object has got unmanaged resources, it must still have a finalizer. Why? The Dispose() method is called by you. There is no guarantee that it's being executed. If the application fails to call the Dispose() method, there's still the GC which calls finalize. So basically doing unmanaged-resource cleanup in Dispose is just a performance improvement (which, under some circumstances, may be very important, unless you want to plug in a few more gigabytes of RAM into the computer...).
If you plan to use a finalizer i absolutely urge you to read the docs on it, because there's quite a few things which i didn't cover here. See Implementing Finalize and Dispose to Clean Up Unmanaged Resources
Your example
To come back to your example, after you construct a AbstractEntityViewModel, it will stay alive as long as the AbstractEntity you've passed to the AbstractEntityViewModel stays alive and vice versa.
But when neither of those two are referenced by a GC root, both of them are garbage collected.
If you detach the event handler, the AbstractEntityViewModel (or rather it's concrete sub-class instance) can be garbage collected even if the AbstractEntity can't.
Also see: Understanding Garbage Collection in .NET
Long and short of it is yes. The secondary object can not be disposed of if the AbstractEntity object still has a reference to it. IF there is a chance that the object will be disposed and the Event is still around (this holds true for static events too) then you need to manually remove the eventhandler or the object will not be disposed.
Events can be though of as being a primitive observer implementation: The subject retains a handler to every subscribed observer, meaning they are unable to be garbage collected. To allow the observer to be garbage collected, it must be removed as an observer from the subject.
The only time where event handlers do not need to be manually removed are when the subject and the observer are the same instance, as the garbage collector will detect the circular reference and subsequently finalize the object.

Adding and Removing Event Handler in .net

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 .

When are reference-type attached properties (DependencyProperty) released?

Say I want to make an attached property that attaches a list of object references to a view instance (a DependencyObject/FrameworkElement)...
When does it release all of those references? Will it call Dispose on attached property values if they implement it?
Its perhaps easier to think that "references" never actually get "released". They simply fall in to disuse and can no longer be found by following any chain of reference from the global space or any thread stack. They are then considered garbage and at some point the collector will come and collect the memory they occupy. If they have finalisers it will not collect the memory immediately but place the object on a queue that will call the finaliser first.
A FrameworkElement should not, for all sorts of reasons, call Dispose on any reference held in its value dictionary when it is being unloaded. Primarly because it can't know that its responsible for doing that.
Imagine a scenario in which code elsewhere created a disposable object and also attached it to a framework element. What would happen if that code later attempted to use the object only to find that the framework element had taken it upon itself to dispose it?
It is the responsibility of the code that creates a disposable object to ensure that its disposed at the appropriate point.
Think of dependency properties as key-value pairs in DependencyObjects. When you assign a value to an attached dependency property (or a regular dependency property), this value is put into the dictionary. That means items in the list will be collected by garbage collector when the view itself is garbage collected. Dispose behavior is usual too.

Can I make a C# object's lifetime depend on another object?

I have an object (Delegate) which needs to stay alive (not garbage collected) while another object (TargetObject) is alive. I want Delegate to be garbage collected when TargetObject is collected (or at least available for collection).
The difficulty is that I don't want to need to reference Delegate from TargetObject since I want it to work for existing objects unaware of Delegate, and I don't want to affect the lifetime of TargetObject. Is this at all possible?
Thanks.
Edit: Thanks for the responses so far. I'll try to clarify what I'm up to.
I'm trying to implement weak events but I'm not a fan of the WeakEventManager (particularly IWeakEventListener). I want to hold a weak reference to a delegate event handler (Delegate) which points to a method in object TargetObject. There needs to be a strong reference to Delegate while TargetObject is alive to keep Delegate alive, but if something with a longer lifetime references Delegate, it keeps TargetObject alive (defeating the purpose of the weak event).
It would be nice if objects subscribing to weak events didn't have to have any special implementation details such as having to hold on to a collection of delegates.
Edit Edit: Changed 'A' to 'Delegate' and 'B' to 'TargetObject'
Holy necro, but ConditionalWeakTable does just what you needed. It allows associating values with arbitrary keys, with the key value pairs as ephemerons (exactly what you were looking for, 2 years ago now.. unfortunately .NET 4 wasn't available then).
Even without ConditionalWeakTable a solution could have been a Dictionary<WeakReference, Delegate>, with periodic sweeping to remove old dead values (ie whenever the Dictionary doubles in size, remove all dead pairs). With this solution if a Delegate refers to TargetObject it'd prevent collection of the pair though - a problem ConditionalWeakTable was designed to resolve.
Just posting this in case anyone might find it useful.
This sounds like a design issue to me. If B doesn't need to know about the instance of A, why do you care about whether A is alive or not?
You can possibly do this using a container object with a weak reference to B and a strong reference to A, and a timer periodically checking whether the weak reference is still alive... but it would be a pretty grotty hack.
If you can explain why you think you need this, we may be able to suggest a better approach.
Why don't you just reference A from B?
That will keep A alive and does not require A to be aware of B...
I don't think it's good design to have an "alive" object that doesn't have any references to it.
You could always create a static List with references to objects that should stay alive, but of course you'd have to manage that yourself.
I don't see a clean solution for that, but maybe some of the super-beings on StackOverflow will come up with a solution.
Throw an event in the destructor (finalize) method of B, and write a handler for that event that kills A.

Categories

Resources