Thursday, October 04, 2007 6:23 PM
Hi folks need some advice....
I read that having a class subscribe to events raised by another class creates a reference between the classes that could stop garbage collection. For example a logging class may subscribe to an event in another class, the logging class now references the other class and so the other class won't be garbage collected until the logging class unsubscribes to the event. Can someone just confirm if is this true?
If this true does that mean it would be a good practise for every class that you have, which raises an event, to have a Dispose pattern so that all it's events can be unsubscribed, making it avaliable for garbage collection?
Thursday, October 04, 2007 11:53 PM
The event publisher will maintain a reference to the event subscriber.
This reference is only one way. So, nothing related to the event handling is stopping the publisher from being garbage collected. However, a subscriber will not be garbage collected before it unregisters from the event or the publisher is garbage collected, whichever comes first.
The warning you mention often occurs in the context of events on "singleton" or "static" classes. Because these objects are long lived, their subscribers will not be garbage collected until they are unregistered.
To make this concrete, in your logging example, the logger is the subscriber, so it will not be collected. This should not be a problem because I image that you would only have a small number of long-lived loggers.
Friday, October 05, 2007 9:18 AM
Hi, thanks for taking the time to reply.
That basically confirms what the book was saying and what appeared to be happening in some experiments I did. It's good to get confirmation though. Although it's perhaps not a practise to do in all circumstances I think removing this behaviour of event handling, for at least medium to long living objects, should be covered with the Dispose pattern. For example when some component is finished with an object that acts like an event publisher then Dispose should be called on that publisher so that it can clear / force the unsubscription of its events and allowing out of scope subcribers to be collected.
Thats really good to know, I'll need to make a note of that.
Saturday, October 06, 2007 9:03 AM
I must admit that I am a little confused about this.
Derek Smyth wrote:
"For example a logging class may subscribe to an event in another class, the logging class now references the other class and so the other class won't be garbage collected until the logging class unsubscribes to the event."
"So, nothing related to the event handling is stopping the publisher from being garbage collected".
Don't the two statements say the opposite?
Since this is a .NET forum, I presume that you are talking about .NET events (not Win32 events) and a .NET event is nothing but a delegate with some eventhandlers in the invocation list and RaiseEvent is nothing but another word for delegate.Invoke. When you subscribe to an event, the eventhandler is added to the invocation list of the event delegate. I find it very logical that if an object has one or more non-empty event delegates, it will not be garbage collected because other programs depend on the events from this object. It is easy to check for the garbage collector. This corresponds to the post of Derek Smyth.
On the other hand, I cannot see how the garbage collecter can see on the subscriber if it subscribes to some events. The only thing, which tells that is the invocation list in the event of the publisher.
Sunday, October 07, 2007 1:16 PM
The statement from Derek should say "logging class", not "other class".
However, your statement that "if an object has one or more non-empty event delegates, it will not be garbage collected" is incorrect. These event delegates are object references, just like any other object reference. An object that references other objects can be collected; it is only not collected when the object is the target of the reference.
Regarding your stement, the GC "can see on the subscriber if it subscribes to some events" because it will determine that there are event delegates that reference it.
(For example, consider a tree data structure where each node has references to parent and child nodes. Once the "rest" of the program no longer references nodes in the tree, the tree will be garbage collected even though the nodes still have references among themselves.)
Tuesday, October 09, 2007 5:56 AM
Thanks for the explanation.
It is difficult to tell whether Derek means what he wrote. I was just triggered by the fact that he marked your answer as being right even though he wrote the opposite.
So if you have an object A, which subscribes to some event(s) raised by object B, object A will be the target of the reference (in the event delegate) and therefore not collected, but nothing prevents object B from being collected. Is that right? In that case, object A will stop working when object B is collected, because it don't receive any events any more.
I must admit that I find it a little unlogical to collect an object, which is still in use (generates events, which is used by other objects), but I know that this can happen to e.g. the SerialPort object, so it is probably just the way it works.
Tuesday, October 09, 2007 9:20 AM
Ah yes there is an error in my original post.... my apologies for any confusion that this may have caused and thanks Carsten for highlighting it.
"For example a logging class may subscribe to an event in another class, the other class now references the logging class and so the logging class won't be garbage collected until the logging class unsubscribes from the event."
Let me reiteriate with a more solid example, this time using the logger class and an employee class. The employee class publishes an event Changed() that is raised after any details of the employee are changed. The logger class subscribes to the Changed() event of the employee and logs any changes. The employee class now holds a reference to the logger class. The logger class cannot be garbage collected.
It's the observer design pattern. The publisher (employee) holds a reference to the subscriber (logger) using a collection of delegates (the loggers event handler). When the event is raised the publisher (employee) invokes each of the delegates in the collection (the loggers event handler is called) and the event is 'handled'.
In this case the logger class cannot be garbage collected because the employee class contains a reference to it.
You might say "well the logger class should live longer than the employee." and yeah it might but it might not, depends on what your application is doing, and this is only one scenario. What I got from BinaryCoders reply, the book I'm reading, and some experiments, is this.
A reference is created between objects when one of them subscribes to the others events. The publisher object holds the reference to the subscriber object. This could affect garbage collection of the subscribing object.