.NET object events and dispose / GC - c#

EDIT: After Joel Coehoorns excellent answer, I understand that I need to be more specific, so I modified my code to be closer to thing I'm trying to understand...
Events: As I understand, in the background the events are "collection" of EventHandlers aka Delegates which will be executed when event raised. So for me it means that if object Y has event E and object X subscribes to event Y.E, then Y will have reference to X, since Y must execute the method located in X, in that way, X can not be collected, and that thing i understand.
//Creates reference to this (b) in a.
a.EventHappened += new EventHandler(this.HandleEvent);
But it is not what Joel Coehoorn tells...
However, there is an issue with events such that sometimes people like to use IDisposable with types that have events. The problem is that when a type X subscribes to events in another type Y, X now has a reference to Y. This reference will prevent Y from being collected.
I not understand how X will reference the Y ???
I modified a bit my example to illustrate my case more closer:
class Service //Let's say it's windows service that must be 24/7 online
{
A _a;
void Start()
{
CustomNotificationSystem.OnEventRaised += new EventHandler(CustomNotificationSystemHandler)
_a = new A();
B b1 = new B(_a);
B b2 = new B(_a);
C c1 = new C(_a);
C c2 = new C(_a);
}
void CustomNotificationSystemHandler(args)
{
//_a.Dispose(); ADDED BY **EDIT 2***
a.Dispose();
_a = new A();
/*
b1,b2,c1,c2 will continue to exists as is, and I know they will now subscribed
to previous instance of _a, and it's OK by me, BUT in that example, now, nobody
references the previous instance of _a (b not holds reference to _a) and by my
theory, previous instance of _a, now may be collected...or I'm missing
something???
*/
}
}
class A : IDisposable
{
public event EventHandler EventHappened;
}
class B
{
public B(A a) //Class B does not stores reference to a internally.
{
a.EventHappened += new EventHandler(this.HandleEventB);
}
public void HandleEventB(object sender, EventArgs args)
{
}
}
class C
{
public C(A a) //Class B not stores reference to a internally.
{
a.EventHappened += new EventHandler(this.HandleEventC);
}
public void HandleEventC(object sender, EventArgs args)
{
}
}
EDIT 2: OK, now it's clear, when subscriber subscribes to a publishers events, it's NOT creates a reference to the publisher in subscriber. Only the reference from publisher to subscriber created (through EventHandler)...in this case when publisher collected by GC before the subscriber (subscribers lifetime is greater then publishers), there's no problem.
BUT...as I know, it's not guaranteed when GC will collect the publisher so in theory, even if subscribers lifetime is greater then publishers, it can happen that subscriber is legal for collection, but publisher is still not collected (I don't know if within closest GC cycle, GC will be smart enough to collect publisher first and then subscriber.
Anyway, in such case, since my subscriber do not have direct reference to publisher and can't unsubscribe the event, I would like to make publisher to implement IDisposable, in order to dispose it before delete all references to him (see in CustomNotificationSystemHandler in my example).
AND AGAIN What I should write in publishers dispose method in order to clear all references to subscribers? should it be EventHappened -= null; or EventHappened = null; or there's no way to do it in such way, and I need to make something like below ???
public event EventHandler EventHappened
{
add
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] + value;
}
remove
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] - value;
}
}

The life time of object B is longer that A, so A may be disposed earlier
It sounds like you are confusing "Disposal" with "Collection"? Disposing an object has nothing to do with memory or garbage collection. To make sure everything is clear, let's break up the two scenarios, and then I'll move on to events at the end:
Collection:
Nothing you do will ever allow A to be collected before it's parent B. As long as B is reachable, so is A. Even though A is private, it's still reachable from any code within B, and so as long as B is reachable, A is considered reachable. This means the garbage collector doesn't know for sure that you're done with it, and will never collect A until it is also safe to collect B. This is true even if you explicitly call GC.Collect() or similar. As long an object is reachable, it will not be collected.
Disposal:
I'm not even sure why you are implement IDisposable here (it has nothing to do with memory or garbage collection), but I'll give you the benefit of the doubt for the moment that we just don't see the unmanaged resource.
Nothing prevents you from Disposing A whenever you want. Just call a.Dispose(), and it's done. The only way the .Net framework will ever call Dispose() for you automatically is at the end of using block. Dispose() is not called during garbage collection, unless you do it as part of the object's finalizer (more on finalizers in a moment).
When implementing IDisposable, you are sending a message to programmers that this type should (maybe even "must") be disposed promptly. There are two correct patterns for any IDisposable object (with two variations on the pattern). The first pattern is to enclose the type itself in a using block. When this is not possible (for example: code such as yours where the type is a member of another type), the second pattern is that the parent type should also implement IDisposable so it can itself then be included in a using block, and it's Dispose() can call your type's Dispose(). The variation on these patterns is to use try/finally blocks instead of a using block, where you call Dispose() in the finally block.
Now on to finalizers. The only time you need to implement a finalizer is for an IDisposable type that originates an unmanaged resource. So, for example, if your type A above is just wrapping a class like SqlConnection, it does not need a finalizer because the finalizer in SqlConnection itself will take care of any needed cleanup. But, if your type A were implementing a connection to a whole new kind of database engine, you would want a finalizer to make sure your connections are closed when the object is collected. Your type B, however, would not need a finalizer, even though it manages/wraps your type A, because type A will take care of finalizing the connections.
Events:
Technically, events are still managed code and shouldn't need to be disposed. However, there is an issue with events such that sometimes people like to use IDisposable with types that have events. The problem is that when a type X subscribes to events in another type Y, Y now has a reference to X. This reference can prevent X from being collected. If you expected Y to have a longer lifetime then X, you can run into problems here, particularly if Y is very long-lived relative to many X's that come and go over time.
To get around this, sometimes programmers will have type Y implement IDisposable, and the purpose of the Dispose() method is to unsubscribe any events so that subscribing objects can also be collected. Technically, this is not the purpose of the Dispose() pattern, but it works well enough that I'm not going to argue about it. There are two things you need to know when using this pattern with events:
You do not need a finalizer if this is the only reason for implementing IDisposable
Instances of your type still need a using or try/finally block, or you haven't gained anything. Otherwise Dispose() will not be called and your objects still cannot be collected.
In this case, your type A is private to type B, and so only type B can subscribe to A's events. Since 'a' is a member of type B, neither is eligible for garbage collection until B is no longer reachable, at which point both will no longer be reachable and the event subscription reference won't count. That means a reference held on B by A's event would not prevent B from being collected. However, if you use the A type in other places, you may still want to have A implement IDisposable to make sure your events are unsubscribed. If you do that, make sure to follow the whole pattern, such that instances of A are enclosed in using or try/finally blocks.

I have added My comments in your sample code.
class A : IDisposable
{
public event EventHandler EventHappened
{
add
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] + value;
}
remove
{
eventTable["EventHappened"] = (EventHandler)eventTable["EventHappened"] - value;
}
}
public void Dispose()
{
//Amit: If you have only one event 'EventHappened',
//you can clear up the subscribers as follows
eventTable["EventHappened"] = null;
//Amit: EventHappened = null will not work here as it is
//just a syntactical sugar to clear the compiler generated backing delegate.
//Since you have added 'add' and 'remove' there is no compiler generated
//delegate to clear
//
//Above was just to explain the concept.
//If eventTable is a dictionary of EventHandlers
//You can simply call 'clear' on it.
//This will work even if there are more events like EventHappened
}
}
class B
{
public B(A a)
{
a.EventHappened += new EventHandler(this.HandleEventB);
//You are absolutely right here.
//class B does not store any reference to A
//Subscribing an event does not add any reference to publisher
//Here all you are doing is calling 'Add' method of 'EventHappened'
//passing it a delegate which holds a reference to B.
//Hence there is a path from A to B but not reverse.
}
public void HandleEventB(object sender, EventArgs args)
{
}
}
class C
{
public C(A a)
{
a.EventHappened += new EventHandler(this.HandleEventC);
}
public void HandleEventC(object sender, EventArgs args)
{
}
}
class Service
{
A _a;
void Start()
{
CustomNotificationSystem.OnEventRaised += new EventHandler(CustomNotificationSystemHandler)
_a = new A();
//Amit:You are right all these do not store any reference to _a
B b1 = new B(_a);
B b2 = new B(_a);
C c1 = new C(_a);
C c2 = new C(_a);
}
void CustomNotificationSystemHandler(args)
{
//Amit: You decide that _a has lived its life and must be disposed.
//Here I assume you want to dispose so that it stops firing its events
//More on this later
_a.Dispose();
//Amit: Now _a points to a brand new A and hence previous instance
//is eligible for collection since there are no active references to
//previous _a now
_a = new A();
}
}
b1,b2,c1,c2 will continue to exists as is, and I know they will now
subscribed to previous instance of _a, and it's OK by me, BUT in that
example, now, nobody references the previous instance of _a (b not
holds reference to _a) and by my theory, previous instance of _a, now
may be collected...or I'm missing something???
As explained through my comments in the above code, you are not missing anything here :)
BUT...as I know, it's not guaranteed when GC will collect the
publisher so in theory, even if subscribers lifetime is greater then
publishers, it can happen that subscriber is legal for collection, but
publisher is still not collected (I don't know if within closest GC
cycle, GC will be smart enough to collect publisher first and then
subscriber.
Since publisher references subscriber, it can never happen that the subscriber becomes eligible for collection before the publisher but reverse can be true. If publisher gets collected before subscriber then, as you said, there is no problem. If the subscriber belongs to a lower GC generation than publisher then since publisher holds a reference to subscriber, GC will treat the subscriber as reachable and will not collect it. If both belong to same generation, they will be collected together.
since my subscriber do not have direct reference to publisher and
can't unsubscribe the event, I would like to make publisher to
implement IDisposable
Contrary to what some have suggested, I would recommend implementing dispose if at any point you are deterministically sure that the object is no longer required. Simply updating an object reference may not always lead to an object stop publishing events.
Consider the following code:
class MainClass
{
public static Publisher Publisher;
static void Main()
{
Publisher = new Publisher();
Thread eventThread = new Thread(DoWork);
eventThread.Start();
Publisher.StartPublishing(); //Keep on firing events
}
static void DoWork()
{
var subscriber = new Subscriber();
subscriber = null;
//Subscriber is referenced by publisher's SomeEvent only
Thread.Sleep(200);
//We have waited enough, we don't require the Publisher now
Publisher = null;
GC.Collect();
//Even after GC.Collect, publisher is not collected even when we have set Publisher to null
//This is because 'StartPublishing' method is under execution at this point of time
//which means it is implicitly reachable from Main Thread's stack (through 'this' pointer)
//This also means that subscriber remain alive
//Even when we intended the Publisher to stop publishing, it will keep firing events due to somewhat 'hidden' reference to it from Main Thread!!!!
}
}
internal class Publisher
{
public void StartPublishing()
{
Thread.Sleep(100);
InvokeSomeEvent(null);
Thread.Sleep(100);
InvokeSomeEvent(null);
Thread.Sleep(100);
InvokeSomeEvent(null);
Thread.Sleep(100);
InvokeSomeEvent(null);
}
public event EventHandler SomeEvent;
public void InvokeSomeEvent(object e)
{
EventHandler handler = SomeEvent;
if (handler != null)
{
handler(this, null);
}
}
~Publisher()
{
Console.WriteLine("I am never Printed");
}
}
internal class Subscriber
{
public Subscriber()
{
if(MainClass.Publisher != null)
{
MainClass.Publisher.SomeEvent += PublisherSomeEvent;
}
}
void PublisherSomeEvent(object sender, EventArgs e)
{
if (MainClass.Publisher == null)
{
//How can null fire an event!!! Raise Exception
throw new Exception("Booooooooommmm");
//But notice 'sender' is not null
}
}
}
If you run the above code, more often than not you will receive the 'Booooooooommmm'. Hence idea is that event publisher must stop firing events when we are sure that its life is up.
This can be done through Dispose method.
There are two ways to achieve this:
Set a flag 'IsDisposed' and check it before firing any event.
Clear up the event subscribers list (as suggested in my comments in your code).
Benefit of 2 is that you release any reference to the subscribers, thereby enabling there collection (as I explained earlier even if the publisher is garbage but belongs to higher generation then it may still prolong collection of lower generation subscribers).
Though, admittedly, it will be quite rare that you experience the demonstrated behavior due to 'hidden' reachability of the publisher but as you can see benefits of 2 are clear and are valid for all event publishers especially long living ones (Singletons anybody!!!). This itself makes it worth to implement Dispose and go with 2.

Contrary to what some other answers claim, events whose publisher's GC lifetime may exceed a subscriber's useful lifetime should be regarded as unmanaged resources. The term "unmanaged" in the phrase "unmanaged resource" doesn't mean "completely outside the world of managed code", but rather relates to whether objects require cleanup beyond that provided by the managed garbage collector.
For example, a collection may expose a CollectionChanged event. If objects of some other type which subscribes to such an event are repeatedly created and abandoned, the collection may end up holding a delegate reference to each and every such object. If such creation and abandonment happens e.g. once per second (as might happen if the object in question were created in a routine that updates a UI window) the number of such references could grow by more than 86,000 for each day that the program was running. Not a big problem for a program which is never run for more than a few minutes, but an absolute killer for a program which could be run for weeks at a time.
It's really unfortunate that Microsoft didn't come up with a better event-cleanup pattern in vb.net or C#. There's seldom any reason why a class instance which subscribes to events shouldn't clean them up before it's abandoned, but Microsoft did nothing to facilitate such cleanup. In practice, one can get away with abandoning objects that are subscribed to events sufficiently often (because the event publisher will go out of scope around the same time as the subscriber) that the annoying level of effort necessary to ensure events get properly cleaned up doesn't seem worthwhile. Unfortunately, it's not always easy to predict all the cases where an event publisher might live longer than expected; if many classes leave events dangling, it's possible for huge amounts of memory to be uncollectable because one of the event subscriptions happens to belong to a long-lived object.
Addendum in response to edit
If X were to subscribe to an event from Y and then abandon all references to Y, and if Y became eligible for collection, X would not prevent Y from being collected. That would be a good thing. If X were to keep a strong reference to Y for the purpose of being able to dispose of it, such reference would prevent Y from being collected. That might arguably not be such a good thing. In some situations it would be better for X to keep a long WeakReference (one constructed with the second parameter set to true) to Y rather than a direct reference; if the target of the WeakReference is non-null when X is Disposed, it will have to unsubscribe from Y's event. If the target is null, it can't unsubscribe but it won't matter, because by then Y (and its reference to X) will have completely ceased to exist. Note that in the unlikely event that Y dies and is resurrected, X will still want to unsubscribe its event; using a long WeakReference will ensure that can still happen.
While some would argue that X shouldn't bother keeping a reference to Y, and Y should simply be written to use some sort of weak event dispatching, such behavior is not correct in the general case because there's no way for Y to tell whether X would do anything that other code might care about even if Y holds the only reference to X. It is entirely possible that X might hold a reference to some strongly-rooted object, and might do something to that other object within its event handler. The fact that Y holds the only reference to X should not imply that no other objects are "interested" in X. The only generally-correct solution is to have objects which are no longer interested in other objects' events notify the latter objects of that fact.

I would have my class B implements IDisposable as well and in it's dispose routine, I would first check whether A is not null and then dispose A. By using this approach you have to just make sure to dispose the last of your class and the internals will handle all other dispose.

MSDN Reference
"To prevent your event handler from being invoked when the event is raised, unsubscribe from the event. 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."
"When all subscribers have unsubscribed from an event, the event instance in the publisher class is set to null."

You don't need to unhook event handlers when disposing of an object, although you may want to. By that I mean that the GC will clean up event handlers just fine without any intervention on your part, however depending on the scenario you may want to remove those event handlers before the GC does in order to prevent the handler being called when you weren't expecting it.
In your example I think you have your roles reversed - class A shouldn't really be unsubscribing event handlers added by others and has no real need to remove event handlers eiether, as it can instead just stop raising those events!
Suppose however that the situation is reversed
class A
{
public EventHandler EventHappened;
}
class B : IDisposable
{
A _a;
private bool disposed;
public B(A a)
{
_a = a;
a.EventHappened += this.HandleEvent;
}
public void Dispose(bool disposing)
{
// As an aside - if disposing is false then we are being called during
// finalization and so cannot safely reference _a as it may have already
// been GCd
// In this situation we dont to remove the handler anyway as its about
// to be cleaned up by the GC anyway
if (disposing)
{
// You may wish to unsubscribe from events here
_a.EventHappened -= this.HandleEvent;
disposed = true;
}
}
public void HandleEvent(object sender, EventArgs args)
{
if (disposed)
{
throw new ObjectDisposedException();
}
}
}
If its possible for A to continue raising events even after B has been disposed, and the event handler for B could do something that may cause either an exception or some other unexpected behaviour if B is disposed then its probably a good idea to unsubscribe from this event first.

The object A references B through EventHandler delegate(A has an instance of EventHandler wich references B). B don't have any reference to A. When A is set to null it will be collected and the memory will be freed.
So you don't need to clear anything in this case.

Related

Do you need to / is it beneficial to unregister events before creating a new instance of an object? [duplicate]

If my software has two object instances, one of which is subscribed to the events of the other. Do I need to unsubscribe them from one another before they are orphaned for them to be cleaned up by the garbage collector? Or is there any other reason why I should clear the event relationships? What if the subscribed to object is orphaned but the subscriber is not, or vise versa?
Yes you do. The event publishers are holding references to the objects, and would prevent them from being garbage collected.
Let's look at an example to see what happens. We have two classes; one exposes an event, the other consumes it:
class ClassA
{
public event EventHandler Test;
~ClassA()
{
Console.WriteLine("A being collected");
}
}
class ClassB
{
public ClassB(ClassA instance)
{
instance.Test += new EventHandler(instance_Test);
}
~ClassB()
{
Console.WriteLine("B being collected");
}
void instance_Test(object sender, EventArgs e)
{
// this space is intentionally left blank
}
}
Note how ClassB does not store a reference to the ClassA instance; it merely hooks up an event handler.
Now, let's see how the objects are collected. Scenario 1:
ClassB temp = new ClassB(new ClassA());
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();
We create a ClassB instance and hold a reference to it through the temp variable. It gets passed a new instance of ClassA, where we do not store a reference to it anywhere, so it goes out of scope immediately after the ClassB constructor is done. We have the garbage collector run once when ClassA has gone out of scope, and once when ClassB as gone out of scope. The output:
Collect 1
A being collected
Collect 2
B being collected
Scenario 2:
ClassA temp = new ClassA();
ClassB temp2 = new ClassB(temp);
temp2 = null;
Console.WriteLine("Collect 1");
GC.Collect();
Console.ReadKey();
temp = null;
Console.WriteLine("Collect 2");
GC.Collect();
Console.ReadKey();
A new instance of ClassA is created and a reference to it is stored in the temp variable. Then a new instance of ClassB is created, getting the ClassA instance in temp passed to it, and we store a reference to it in temp2. Then we set temp2 to null, making the ClassB instance going out of scope. As before, we have the garbage collector run after each instance has gone out of scope. The output:
Collect 1
Collect 2
B being collected
A being collected
So, to conclude; if the instance that exposes an event goes out of scope, it becomes available for garbage collection, regardless of whether there are event handlers hooked up or not. If an instance that has an event handler hooked up to an event in another instance, it will not be available for garbage collection until either the event handler is detached, or the instance to which the event handler is attached becomes available for garbage collection.
You only need to unhook events if the object exposing the events is long-lived, but the object hooking the event would otherwise be short-lived (and get garbage collected fairly quickly).
In this case, failing to unhook will cause what amounts to a memory leak, because your short-lived object will not be able to be GCed -- because the event in the long-lived object holds onto a delegate, which holds a reference to the short-lived object. Since the short-lived object is still referenced by that delegate, it can't get garbage-collected.
Static events are long-lived by definition -- they live until the program exits. If you hook a static event, you definitely should unhook it when you're done.
If both objects are about to be orphaned, unhooking isn't necessary.
Subscribing to an event results in a strong reference to the subscriber. This is because, under the covers, events are delegates, and delegates to instance methods are a combination of the object reference and the actual method. If you don't unsubscribe, the publisher will continue to maintain the references, and the subscribing objects never get truly orphaned (and GC'ed) as long as the publisher is alive.
The reverse isn't true i.e. the subscribed object doesn't have any reference to the publisher.

Garbage collection of unreferenced object with live event handler

In the following program...
using System;
class Program
{
static Parent parent;
static void Main( string[] args )
{
parent = new Parent();
// The program hereafter runs for a long time and occasionally
// causes parent.SomeEvent to be raised.
}
}
class Parent
{
public event EventHandler SomeEvent;
public Parent()
{
new Handler( this );
}
}
class Handler
{
public Handler( Parent parent )
{
parent.SomeEvent += parent_SomeEvent;
}
void parent_SomeEvent( object sender, EventArgs e )
{
// Does something important here.
}
}
Notice that the instantiated Handler object is not referenced, although it has subscribed to SomeEvent. Is it possible that, after the program is running for a while, the garbage collector may decide to eliminate the Handler instance and its parent_SomeEvent handler will therefore no longer be called whenever parent.SomeEvent is raised?
I need this clarification for an app I am writing. There are many Handler-like objects that are instantiated as shown above, without being referenced. The central purpose of Handler is to subscribe to SomeEvent. There are no useful methods to call on a reference to the Handler instance, so I would be fine not referencing it otherwise. I haven't encountered any problems while debugging. But now I am concerned that issues may arise after deployment when the app is running for long periods of time and the garbage collector is more active.
The instantiated object of your Handler class will not be garbage collected until all references to that object are removed.
Thus, until you unsubscribe all your event handlers, the object will live. Because the subscribed event handler is also another "reference" that connects the Parent instance to the Handler instance.
Is it possible that, after the program is running for a while, the
garbage collector may decide to eliminate the Handler instance and its
parent_SomeEvent handler will therefore no longer be called whenever
parent.SomeEvent is raised?
That's exactly the reason why the GC only collects "unreferenced" objects from the heap. Your scenario would result in undefined NullReferenceExceptions, completely dependent on whenever the GC decides to delete objects. So luckily that's not the case :).
Furthermore, the GC is intelligent enough to determine isolated pools of unreferenced objects (unreferenced islands). So in the scenario your parent object also gets unreferenced, than the GC will determine the whole chain of objects are unreferenced (the Parent object, the event subscription, and the handler object) and will collect them all together on the next collect cycle.
If I may, I'd recommend this MSDN article. Gives you a nice overview of the broad concept of garbage collection in .NET. Very useful to keep in mind while coding.
Program exists the whole time, and it's referring an instance of Parent, and thus Parent will never be garbage collected (until the program ends).
Parent keeps a collection of delegates through it's event handler SomeEvent, so any delegates in there won't be garbage collected.
So in short, no, it won't be garbage collected.
When you run your program, the Parent class holds a reference to the EventHandler delegate instance you're creating in the Handler constructor, and the delegate instance holds a reference to the Handler instance. So the Handler instance will not be garbage collected as long as there is a reference to the Parent instance.

How do events cause memory leaks in C# and how do Weak References help mitigate that?

There are two ways (that I know of) to cause an unintentional memory leak in C#:
Not disposing of resources that implement IDisposable
Referencing and de-referencing events incorrectly.
I don't really understand the second point. If the source object has a longer lifetime than the listener, and the listener doesn't need the events anymore when there are no other references to it, using normal .NET events causes a memory leak: the source object holds listener objects in memory that should be garbage collected.
Can you explain how events can cause memory leaks with code in C#, and how I can code to get around it using Weak References and without Weak References?
When a listener attaches an event listener to an event, the source object will get a reference to the listener object. This means that the listener cannot be collected by the garbage collector until either the event handler is detached, or the source object is collected.
Consider the following classes:
class Source
{
public event EventHandler SomeEvent;
}
class Listener
{
public Listener(Source source)
{
// attach an event listner; this adds a reference to the
// source_SomeEvent method in this instance to the invocation list
// of SomeEvent in source
source.SomeEvent += new EventHandler(source_SomeEvent);
}
void source_SomeEvent(object sender, EventArgs e)
{
// whatever
}
}
...and then the following code:
Source newSource = new Source();
Listener listener = new Listener(newSource);
listener = null;
Even though we assign null to listener, it will not be eligible for garbage collection, since newSource is still holding a reference to the event handler (Listener.source_SomeEvent). To fix this kind of leak, it is important to always detach event listeners when they are no longer needed.
The above sample is written to focus on the problem with the leak. In order to fix that code, the easiest will perhaps be to let Listener hold on to a reference to Source, so that it can later detach the event listener:
class Listener
{
private Source _source;
public Listener(Source source)
{
_source = source;
// attach an event listner; this adds a reference to the
// source_SomeEvent method in this instance to the invocation list
// of SomeEvent in source
_source.SomeEvent += source_SomeEvent;
}
void source_SomeEvent(object sender, EventArgs e)
{
// whatever
}
public void Close()
{
if (_source != null)
{
// detach event handler
_source.SomeEvent -= source_SomeEvent;
_source = null;
}
}
}
Then the calling code can signal that it is done using the object, which will remove the reference that Source has to ´Listener`;
Source newSource = new Source();
Listener listener = new Listener(newSource);
// use listener
listener.Close();
listener = null;
Read Jon Skeet's excellent article on events. It's not a true "memory leak" in the classic sense, but more of a held reference that hasn't been disconnected. So always remember to -= an event handler that you += at a previous point and you should be golden.
There are, strictly speaking, no "memory leaks" within the "sandbox" of a managed .NET project; there are only references held longer than the developer would think necessary. Fredrik has the right of it; when you attach a handler to an event, because the handler is usually an instance method (requiring the instance), the instance of the class containing the listener stays in memory as long as this reference is maintained. If the listener instance contains references to other classes in turn (e.g. backreferences to containing objects), the heap can stay quite large long after the listener has gone out of all other scopes.
Maybe someone with a bit more esoteric knowledge of Delegate and MulticastDelegate can shed some light on this. The way I see it, a true leak COULD be possible if all of the following were true:
The event listener requires external/unmanaged resources to be released by implementing IDisposable, but it either does not, or
The event multicast delegate does NOT call the Dispose() methods from its overridden Finalize() method, and
The class containing the event does not call Dispose() on each Target of the delegate through its own IDisposable implementation, or in Finalize().
I've never heard of any best practice involving calling Dispose() on delegate Targets, much less event listeners, so I can only assume the .NET developers knew what they were doing in this case. If this is true, and the MulticastDelegate behind an event tries to properly dispose of listeners, then all that is necessary is proper implementation of IDisposable on a listening class that requires disposal.

Finalizers accessing managed stuff

I am well aware that finalizers are typically used to control unmanaged resources. Under what circumstances may a finalizer deal with managed ones?
My understanding is that presence in the finalizer queue will prevent any object, or objects strongly referenced thereby, from being collected, but it will not (of course) protect them from finalization. In the normal course of events, once an object is finalized it will be removed from the queue and any objects it references will no longer be protected from collection on the next GC pass. By the time a finalizer is called, the finalizers may have been called for any combination of objects referred to by the object; one cannot rely upon finalizers being called in any particular sequence, but the object references one holds should still be valid.
It's pretty clear that a finalizer must never acquire locks, nor attempt to create a new object. Suppose, however, that I have an object that subscribes to some events, and another object which actually uses the events. If the latter object becomes eligible for garbage collection I want to have the former object unsubscribe from events as soon as practical. Note that the former object will never become eligible for finalization until no subscriptions for it are held by any live object.
Would it be practical to have a lock-free linked-list stack or queue of objects which needed to be unsubscribed, and have the main object's finalizer put a reference to the other object on the stack/queue? The linked-list item object would have to be allocated when the main object was created (since allocation within the finalizer would be forbidden), and it would probably be necessary to use something like a timer event to poll the queue (since the event unsubscription would have to run outside the finalizer thread, and it would probably be silly to have a thread whose sole purpose was to wait for something to appear on the finalizer queue), but if the finalizer could safely reference its pre-allocated linked-list object and the main queue object associated with its class, it could allow the events to be unsubscribed within 15 seconds or so of finalization.
Would that be a good idea? (Notes: I'm using .net 2.0; also, an attempt to add to the stack or queue might spin a few times on Threading.Interlocked.CompareExchange, but I wouldn't expect that it should ever be stuck very long).
EDIT
Certainly any code which subscribes events should implement iDisposable, but disposable things aren't always disposed properly. If there were, there wouldn't be any need for finalizers.
My scenario of concern would be something like the following: a class implementing iEnumerator(of T) hooks onto a changeNotify event of its associated class so that an enumeration can be sensibly handled if the underlying class changes (yes, I know Microsoft thinks all enumerators should simply give up, but sometimes an enumerator which can keep working will be more useful). It's quite possible that an instance of the class might be enumerated many thousands or even millions of times over the course of days or weeks, but not be updated at all during that time.
Ideally, the enumerator would never be forgotten about without being disposed, but enumerators are sometimes used in contexts where "foreach" and "using" aren't applicable (e.g. some enumerators support nested enumeration). A carefully-designed finalizer might allow a means to deal with this scenario.
Incidentally, I'd require that any enumeration which is supposed to continue through updates must use the generic IEnumerable(of T); the non-generic form, which doesn't handle iDisposable, would have to throw an exception if the collection gets modified.
Suppose, however, that I have an object that subscribes to some events, and another object which actually uses the events. If the latter object becomes eligible for garbage collection I want to have the former object unsubscribe from events as soon as practical. Note that the former object will never become eligible for finalization until no subscriptions for it are held by any live object.
If the "latter object" is the one that's using the events, and the "former" object is the one subscribing to the events, the "former" object has to have some way to pass the event info to the "latter" object - meaning it's going to have some reference in place to "latter". Chances are, this will keep the "latter" object from ever being a GC candidate.
That being said, I would recommend avoid this type of managed resource deallocation via the finalizer, unless absolutely necessary. The architecture you're describing seems very fragile, and very tricky to get right. This is probably a better candidate for IDisposable, with the finalizer being the "last ditch" cleanup effort.
Although IDisposable is typically about releasing native resources - it can be about releasing any resource, including your subscription information.
Also, I'd try to avoid having a single global collection of object references - it might make more sense to have your objects internally just use a WeakReference. As soon as the "latter" object is collected, the "former" object's WeakReference would no longer be valid. The next time an event subscription is raised, if the internal WeakReference is no longer valid, you can just unsubscribe yourself. No need for global queues, lists, etc - it should just work...
I'm going to call the objects "publisher" and "subscriber" and restate my understanding of the problem:
In C#, the publisher will (effectively) hold references to the subscribers, preventing subscribers from being garbage collected. What can I do so that the subscriber objects can be garbage collected without explicitly managing the subscriptions?
First, I would recommend doing everything I could to avoid this situation in the first place. Now, I'm going to move on and assume you have, considering you're posting the question anyway =)
Next, I would recommend hooking the add and remove accessors of the publisher's event(s) and using a collection of WeakReferences. You can then automatically unhook those subscriptions whenever the event is invoked. Here's an extremely rough, untested example:
private List<WeakReference> _eventRefs = new List<WeakReference>();
public event EventHandler SomeEvent
{
add
{
_eventRefs.Add(new WeakReference(value));
}
remove
{
for (int i = 0; i < _eventRefs; i++)
{
var wRef = _eventRefs[i];
if (!wRef.IsAlive)
{
_eventRefs.RemoveAt(i);
i--;
continue;
}
var handler = wRef.Target as EventHandler;
if (object.ReferenceEquals(handler, value))
{
_eventRefs.RemoveAt(i);
i--;
continue;
}
}
}
}
Let me make sure I understand -- are you worried about leaks from event subscribers that remain subscribed to a collected event publisher?
If that's the case, then I don't think you have to worry about it.
Here's what I mean assuming that the "former" object is the event subscriber and the "latter" object is the event publisher (raises the event):
The only reason that the subscriber (former) is "subscribed" is because you created a delegate object and passed that delegate to the publisher ("latter").
If you look at the delegate members, it has a reference to the subscriber object and to the method on the subscriber that will be executed. So there is a reference chain that looks like this: publisher --> delegate --> subscriber (publisher references delegate, which references subscriber). It's a 1-way chain -- the subscriber does not hold a reference to delegate.
So, the only root that keeps the delegate around is on the publisher ("latter"). When latter becomes eligible for GC, so does the delegate. Unless there is some special action you want for your subscribers to take when they unsubscribe, they will effectively become unsubscribed when the delegate gets collected -- there is no leak).
Edit
Based on supercat's comments, it sounds like the problem is that the publisher is keeping the subscriber alive.
If that's the problem, then finalizers won't help you. Reason: Your publisher has a real, bonafide reference to your subscriber (via the delegate), and the publisher is rooted (otherise it would be eligible for GC), so your subscribers are rooted, and will not be eligible for finalization or GC.
If you are having trouble with publisher keeping subscriber alive, I would suggest that you search for weak-ref events. Here are a couple links to get you started: http://www.codeproject.com/KB/cs/WeakEvents.aspx http://www.codeproject.com/KB/architecture/observable_property_patte.aspx.
I had to deal with this once as well. Most of the effective patterns involve changing the publisher so that it holds a weak-ref to the delegate. Then you have a new problem -- the delegate isn't rooted, and you hvae to keep it alive somehow. The articles above probably do something like that. Some techniques use reflection.
I used a technique once that did not rely upon reflection. It required that you be able to make changes to the code in both the publisher and the subscriber, though. If you would like to see a sample of that solution, let me know.
Let's try this again. Can you add your event handlers to your publisher like this:
var pub = new Publisher();
var sub = new Subscriber();
var ref = new WeakReference(sub);
EventHandler handler = null; // gotta do this for self-referencing anonymous delegate
handler = (o,e) =>
{
if(!ref.IsAlive)
{
pub.SomeEvent -= handler; // note the self-reference here, see comment above
return;
}
((Subscriber)ref.Target).DoHandleEvent();
};
pub.SomeEvent += handler;
This way, your delegate doesn't keep a direct reference to the subscriber, and automatically unhooks itself whenever the subscriber gets collected. You could implement this as a private static member of the Subscriber class (for the purposes of encapsulation), just make sure it's static to prevent inadvertently holding onto a direct reference to the "this" object.

How to get rid of event handlers safely?

Let's say I have a class A which can fire an event called X. Now I have a class B and in a method I get an instance to A and bind the event to a handler in B:
public void BindEvent(A a)
{
a.X += AEventHandler;
}
I have three questions about this.
Is it true that when I now set the reference to the B instance to null, it won't be garbage collected since the garbage collector thinks it's still in use (thus keeping a useless and potentially interfering copy of B in memory).
What about when I have another object c (of class C) in which I have a reference to A called a ("this.a = new A()"). Then I call "b.BindEvent(this.a)", and in c I set the reference to a to null ("this.a = null"). Will this keep the copy of A in memory because it's referenced through the event in b?
If either or both are true of the above, how can I best circumvent these issues? If I have a whole list of event handlers (say 10 lines like "a.SomeEvent += SomeMethod") should I clean them all up again ("a.SomeEvent -= SomeMethod"). At which time or place in the code should I do these things?
Well it's gotten a bit fuzzy but I'm not sure how to explain in a better way. Please leave a comment if I need to explain something more detailed.
so: A is the publisher and B is the subscriber?
first bullet: if B is the instance with AEventHandler - then it is still in use, so no, it won't get collected unless the a instance is unreachable.
second bullet: huh? (will read again...) If the A and B instances are both unreachable, they will be garbage collected; the event doesn't matter. If A is reachable, then B will stay alive. However, the event subscription never keeps A alive; it is one way... A can keep B alive, but B doesn't keep A alive. Does that cover it?
third bullet: in most cases, the two things have similar life expentency, so it isn't an issue. It only becomes an issue if the thing publishing the event lives a lot longer than the things with the handlers. In which case, you simply need to religiously clean up after yourself - for example: a.X -= AEventHandler. In particular, static events are evil for this reason.
You should really unbind the event handler before destroying the class instance that it relates to. (Using your code as an exmaple.)
public void UnbindEvent(A a)
{
a.X -= AEventHandler;
}
I would also ask, why are you setting class variables to null?
Correct.
Correct.
Why would you want to circumvent this behaviour? It's how the GC is designed to work. If you need to do some clean up when each object is torn down, use the Dispose pattern.
Yes, event are references, if you don't unregister, the object implementing the event handler will not be garbage collected.
You can do this:
Remove all registered event, if A knows when they are not used anymore.
class A
{
// clearing all registrations
private void ClearEvents()
{
X = null;
}
}
Or you unregister in B, if B knows when it doesn't use it anymore. You need to keep a reference to a to be able to unregister.
You could also implement IDisposable.
class B : IDisposable
{
private A registeredToA;
public void BindEvent(A a)
{
registeredToA = a;
registeredToA.X += AEventHandler;
}
public void Dispose()
{
registeredToA.x -= AEventHandler;
}
}
This is a breaking change to your code, because B needs always to be disposed.

Categories