For instance is it necessary to add a Timer instance to a list as I am doing here to prevent the Timer being garbage collected? Tyically if the callback was not anonymous the aswer is yes, but since it is anonymous i imagine the variables in the method block which are accessible in the anonymous method block will only be garbage collected when the anonymous method completes? In which case no need to save ref as I am doing..:
private static List<Timer> timers = new List<Timer>();
public static void RunCallbackAfter(Action callback, int secondsToWait)
{
Timer t = null;
t = new Timer(new TimerCallback(delegate(object state)
{
SomeThread.BeginInvoke(callback);
timers.Remove(t);
}), null, secondsToWait*1000, Timeout.Infinite);
timers.Add(t);
}
The objects referred to by the captured variables in the anonymous method will not be eligible for garbage collection until the delegate created by the anonymous method is eligible for garbage collection.
However, if it's only the Timer which has a reference to the delegate, and nothing else has a reference to the timer, then I suspect both would be eligible for garbage collection, assuming this is indeed the kind of timer which you need to keep a reference to. (I seem to remember that some timers do require this and some don't. I can't remember which is which.)
Also, if you removed the timers.Remove(t) call from within the anonymous method then it wouldn't be capturing t in the first place. It's only captured variables which have prolonged lifetimes... not every variable in the method which contains the anonymous method.
In general, anonymous functions in C# will keep any local variables that they reference alive until the anon function itself is destroyed. Naturally, removing the remove call in this case would remove the reference, meaning the variable would no longer be kept alive by the callback.
However, this here forms a circular reference; unless there's an outside reference the timer and callback could be destroyed simultaneously. I'm not sure if starting a timer counts as an external reference keeping it alive in C#, so I can't answer your question fully, though. If a started timer is treated as having an external reference, then that alone would keep both the timer and callback alive.
No. You don't need to stash away your timer. It would normally be garbage collected, since it is only referenced by your delegate. However, I believe that the Timer constructor places a reference with the underlying runtime, so you should be fine.
Raymond Chen probably has something to say in his blog post: The implementation of anonymous methods in C# and its consequences (part 1)
Your Timer variable t will stay accessible as long as there is a reference to your anonymous method. Your anonymous method will stay referenced until the event has fired. At least that long.
According to Raymond Chen, the c# compiler turns your code into something else, with the context of your method (including the this pointer of the enclosing object) all wrapped up in its own little compiler generated class. So it seems the anonymous method (or delegate) itself contains the reference to the timer.
Oh, and everyone else in this thread are correct: I just blurted out some stuff (and learned about how the C# compiler handles anonymous methods at the same time).
So yes, you have a circular reference. But I'm pretty sure creating a timer should hook that up somewhere in the runtime / windows. Let's have a check.
Using Reflector, you can follow the trail from System.Timer.Timer() through to TimerBase, which has an extern method AddTimerNative. I'm not sure how to peek into that, but I'm going to bet it registers your timer with the OS.
Conclusion: Your timer will not go out of scope, as it will be referenced by the OS until it fires.
Related
Background:
I've a got a main object that live on my app's UI thread. This long-lived parent / container object contains a sub-object as a private member that is internally multi-threaded.
Based on some event published from the child / contained object I'd like the parent object to simply Dispose() the child and recreate it.
The contained object owns some unmanaged resources and well as some large managed memory buffers.
I could create an event handler on the top level object that does this, but this means that the object about to be Disposed will be in the call stack of the method call to about to replace it. (!)
This is because the event handler delegate will be called by one of the child object's state handling functions on it's own thread.
This seems...wrong. No?
In particular, the the child's FireAnEvent() method will resume execution after the delegate calls are processed, except that now execution will resume in the context of an already "disposed" object.
Intuitively, I can't see this leading to good things.
Question:
Is there an established C# pattern to destroy a contained object as a result of it's own event?
Or, is there GC magic that makes such a simple event handler good enough somehow?
Or, am I missing some key bit of understanding?
Calling IDisposable.Dispose() doesn't signal anything special to the .NET framework. The only thing you need to do is remove any references to the object you wish to remove. Once this is done and the object is out of the call stack, it will become a candidate for garbage collection.
Note that your object will not necessarily be garbage collected immediately, or even the next time the GC runs; it is merely an assumed eventuality.
The only purpose of IDisposable is to provide a standard means for requesting that an object clean itself up and release resources. You can hold a reference to a "disposed" object for as long as you like, which will prevent the GC from collecting the object. IDisposable.Dispose() is just another method; technically, you can make it do anything you want.
This question has a very nicely detailed answer that may help you understand IDisposable a bit more: Proper use of the IDisposable interface
as mentioned, an IDisposable object is nothing magical. It just lets you use the using shorthand, which is just a shorthand for:
try { // code in the using block }
catch{}
finally{
disposableObject.Dispose()
}
Have you considered incorporating a third type of object into the mix? It is ill advised that contained object be conscious of their container.
Roughly this would be your workflow:
contained object decides it should be restarted.
contained object frees resources.
contained object writes to a queue on a third object (not the containing object).
containing object accesses the queue when you feel you should create new contained objects and reinstantiates the objects. Alternatively adding to the queue raises an event to the container to empty it.
The third object might seem pointless but it would make your life a lot easier if you ever decided to refactor.
Objects which subscribe to events for the purpose of notification should be prepared to receive notifications at any time, even after they have been disposed. The purpose of a notification is to tell an object to do whatever it needs to do in response to something that has happened. If an object can't do anything useful in response to a notification, it should simply not do anything.
Further, the purpose of Dispose isn't to "destroy" an object, nor the resources it contains, but rather to release it from any obligations it may have had to outside objects, and allow it to release any outside entities from any obligations they might have had toward it. In many cases, an object will be useless once it releasing the services of outside entities that were committed to it, and thus objects which have been disposed cannot be expected to be useful; if, as is likely, a method which is called after Disposed cannot satisfy its duties because necessary outside entities have been released, it should throw ObjectDisposedException rather than failing some other way.
Putting these observations together, while many methods on a disposed object should throw ObjectDisposedException, notification event handler methods should not, since they're instructing the object to "do whatever you need to do to meet your obligations, given that something has happened". If an object has been disposed, it has no obligations. Thus, being disposed doesn't prevent an object from satisfying an event handler contract; instead, it allows the object to meet the contract by silently ("successfully") doing nothing.
Recently I have come across an increasing number of people who have code similar to the following:
private AsynchronousReader r;
public SynchronousReader()
{
r = new AsynchronousReader();
// My practice is to put this here
// and then never remove it and never add it again
// thus cleaning up the code and preventing constant add/remove.
//r.ReadCompleted += this.ReadCompletedCallback;
}
private ReadCompletedCallback()
{
// Remove the callback to "clean things up"...
r.ReadCompleted -= this.ReadCompletedCallback;
// Do other things
}
public Read()
{
r.ReadCompleted += this.ReadCompletedCallback;
// This call completes asynchronously and later invokes the above event
r.ReadAsync();
r.WaitForCompletion();
}
Folks say that this practice is better than the one I indicated above and have given several reasons specific to Silverlight. They state it prevents memory leaks, threading issues, and even that it is the normal practice.
I have not done much Silverlight, but it seems silly to do this still.
Are there any specific reasons one would use this method instead of just rigging up the callback in the constructor once and for the lifetime of the object?
This is as simple as I could make my example. Ignore the fact that it's a sort of wrapper that turns an asynchronous object into a synchronous one. I'm only curious about the way events are added and removed.
In the case you mention it would make sense to hook it up once, but potentially the objects (parent and/or child) may not get garbage collected as the event handlers still reference them.
According to Marc Gavel here
i.e. if we have:
publisher.SomeEvent += target.SomeHandler;
then "publisher" will keep "target" alive, but "target" will not keep
"publisher" alive.
A more important point to bear in mind might be the lifespan of the child object. If it is the same as the parent, then one-off subscription in the constructor makes more sense. If it is dynamic you will likely want to remove the handlers as I have seen them leak (resulting in multiple callbacks).
Note: If the constructor-only method turns out to leak objects, you can always put an unsubscribe in the Dispose() I guess, but I can't say I have ever seen that.
It sounds like you have two issues:
You're attempting to reuse an object that really should only be used once.
That object needs to get properly cleaned up.
You should really either only use an instance of the SynchronousReader object only once (thus avoiding the two async calls racing with one failing to finish like you mentioned elsewhere) or you should implement IDisposable in order to unsubscribe from the event and prevent the memory leak.
A third solution might be possible: keep the single instance of SynchronousReader, but each call to SynchronousReader.Read would create a new instance of AsynchronousReader (rather than storing it as a private field within the instance). Then you could keep most of the code above which you don't like, but which properly handles event subscriptions.
While looking at the Timer documentation I ran across the following example with this comment:
// Normally, the timer is declared at the class level,
// so that it stays in scope as long as it is needed.
// If the timer is declared in a long-running method,
// KeepAlive must be used to prevent the JIT compiler
// from allowing aggressive garbage collection to occur
// before the method ends. You can experiment with this
// by commenting out the class-level declaration and
// uncommenting the declaration below; then uncomment
// the GC.KeepAlive(aTimer) at the end of the method.
//System.Timers.Timer aTimer;
code in between
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
Does this mean that the GC in C# is allowed to garbage collect local variables even if it would have side effects? Presumably because I'm not accessing the timer afterwards again the GC can collect it earlier?
Not sure I'm a fan of such an optimization if I understand this correctly (but then I probably don't ;) )
Yes, GC might collect local variable before ending of the scope, as soon as after last use of the variable. Putting GC.KeepAlive at the end of the method ensures that the variable will be 'alive' until the KeepAlive call.
C# is imperative language so the GC hasn't been designed to know anything about side effects.
As far as I understand the GC, it will mark any variable or object that it believes is no longer needed as a candidate for Garbage Collection during the next GC cycle. I'm not certain I understand the particular application here, but I do know there are cases where the GC might mark a resource for collection when it is still needed (but does not appear so due to the way the code is written).
Normally, during methods, an object or variable stays in scope for the duration of the method call, but if the method call lasts longer than the time between GC cycles, the GC might see your Timer object as out of scope and mark it for collection. Adding the GC.KeepAlive method forces the GC to wait until the method exits before acting on the Timer object.
I have a timer in C# which executes some code inside it's method. Inside the code I'm using several temporary objects.
If I have something like Foo o = new Foo(); inside the method, does that mean that each time the timer ticks, I'm creating a new object and a new reference to that object?
If I have string foo = null and then I just put something temporal in foo, is it the same as above?
Does the garbage collector ever delete the object and the reference or objects are continually created and stay in memory?
If I just declare Foo o; and not point it to any instance, isn't that disposed when the method ends?
If I want to ensure that everything is deleted, what is the best way of doing it:
with the using statement inside the method
by calling dispose method at the end
by putting Foo o; outside the timer's method and just make the assignment o = new Foo() inside, so then the pointer to the object is deleted after the method ends, the garbage collector will delete the object.
1.If I have something like Foo o = new Foo(); inside the method, does that
mean that each time the timer ticks,
I'm creating a new object and a new
reference to that object?
Yes.
2.If I have string foo = null and then I just put something temporal in foo,
is it the same as above?
If you are asking if the behavior is the same then yes.
3.Does the garbage collector ever delete the object and the reference or
objects are continually created and
stay in memory?
The memory used by those objects is most certainly collected after the references are deemed to be unused.
4.If I just declare Foo o; and not point it to any instance, isn't that
disposed when the method ends?
No, since no object was created then there is no object to collect (dispose is not the right word).
5.If I want to ensure that everything is deleted, what is the best way of
doing it
If the object's class implements IDisposable then you certainly want to greedily call Dispose as soon as possible. The using keyword makes this easier because it calls Dispose automatically in an exception-safe way.
Other than that there really is nothing else you need to do except to stop using the object. If the reference is a local variable then when it goes out of scope it will be eligible for collection.1 If it is a class level variable then you may need to assign null to it to make it eligible before the containing class is eligible.
1This is technically incorrect (or at least a little misleading). An object can be eligible for collection long before it goes out of scope. The CLR is optimized to collect memory when it detects that a reference is no longer used. In extreme cases the CLR can collect an object even while one of its methods is still executing!
Update:
Here is an example that demonstrates that the GC will collect objects even though they may still be in-scope. You have to compile a Release build and run this outside of the debugger.
static void Main(string[] args)
{
Console.WriteLine("Before allocation");
var bo = new BigObject();
Console.WriteLine("After allocation");
bo.SomeMethod();
Console.ReadLine();
// The object is technically in-scope here which means it must still be rooted.
}
private class BigObject
{
private byte[] LotsOfMemory = new byte[Int32.MaxValue / 4];
public BigObject()
{
Console.WriteLine("BigObject()");
}
~BigObject()
{
Console.WriteLine("~BigObject()");
}
public void SomeMethod()
{
Console.WriteLine("Begin SomeMethod");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("End SomeMethod");
}
}
On my machine the finalizer is run while SomeMethod is still executing!
The .NET garbage collector takes care of all this for you.
It is able to determine when objects are no longer referenced and will (eventually) free the memory that had been allocated to them.
Objects are eligable for garbage collection once they go out of scope become unreachable (thanks ben!). The memory won't be freed unless the garbage collector believes you are running out of memory.
For managed resources, the garbage collector will know when this is, and you don't need to do anything.
For unmanaged resources (such as connections to databases or opened files) the garbage collector has no way of knowing how much memory they are consuming, and that is why you need to free them manually (using dispose, or much better still the using block)
If objects are not being freed, either you have plenty of memory left and there is no need, or you are maintaining a reference to them in your application, and therefore the garbage collector will not free them (in case you actually use this reference you maintained)
Let's answer your questions one by one.
Yes, you make a new object whenever this statement is executed, however, it goes "out of scope" when you exit the method and it is eligible for garbage collection.
Well this would be the same as #1, except that you've used a string type. A string type is immutable and you get a new object every time you make an assignment.
Yes the garbage collector collects the out of scope objects, unless you assign the object to a variable with a large scope such as class variable.
Yes.
The using statement only applies to objects that implement the IDisposable interface. If that is the case, by all means using is best for objects within a method's scope. Don't put Foo o at a larger scope unless you have a good reason to do so. It is best to limit the scope of any variable to the smallest scope that makes sense.
Here's a quick overview:
Once references are gone, your object will likely be garbage collected.
You can only count on statistical collection that keeps your heap size normal provided all references to garbage are really gone. In other words, there is no guarantee a specific object will ever be garbage collected.
It follows that your finalizer will also never be guaranteed to be called. Avoid finalizers.
Two common sources of leaks:
Event handlers and delegates are references. If you subscribe to an event of an object, you are referencing to it. If you have a delegate to an object's method, you are referencing it.
Unmanaged resources, by definition, are not automatically collected. This is what the IDisposable pattern is for.
Finally, if you want a reference that does not prevent the object from getting collected, look into WeakReference.
One last thing: If you declare Foo foo; without assigning it you don't have to worry - nothing is leaked. If Foo is a reference type, nothing was created. If Foo is a value type, it is allocated on the stack and thus will automatically be cleaned up.
Yes
What do you mean by the same? It will be re-executed every time the method is run.
Yes, the .Net garbage collector uses an algorithm that starts with any global/in-scope variables, traverses them while following any reference it finds recursively, and deletes any object in memory deemed to be unreachable. see here for more detail on Garbage Collection
Yes, the memory from all variables declared in a method is released when the method exits as they are all unreachable. In addition, any variables that are declared but never used will be optimized out by the compiler, so in reality your Foo variable will never ever take up memory.
the using statement simply calls dispose on an IDisposable object when it exits, so this is equivalent to your second bullet point. Both will indicate that you are done with the object and tell the GC that you are ready to let go of it. Overwriting the only reference to the object will have a similar effect.
The garbage collector will come around and clean up anything that no longer has references to it. Unless you have unmanaged resources inside Foo, calling Dispose or using a using statement on it won't really help you much.
I'm fairly sure this applies, since it was still in C#. But, I took a game design course using XNA and we spent some time talking about the garbage collector for C#. Garbage collecting is expensive, since you have to check if you have any references to the object you want to collect. So, the GC tries to put this off as long as possible. So, as long as you weren't running out of physical memory when your program went to 700MB, it might just be the GC being lazy and not worrying about it yet.
But, if you just use Foo o outside the loop and create a o = new Foo() each time around, it should all work out fine.
As Brian points out the GC can collect anything that is unreachable including objects that are still in scope and even while instance methods of those objects are still executing. consider the following code:
class foo
{
static int liveFooInstances;
public foo()
{
Interlocked.Increment(ref foo.liveFooInstances);
}
public void TestMethod()
{
Console.WriteLine("entering method");
while (Interlocked.CompareExchange(ref foo.liveFooInstances, 1, 1) == 1)
{
Console.WriteLine("running GC.Collect");
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine("exiting method");
}
~foo()
{
Console.WriteLine("in ~foo");
Interlocked.Decrement(ref foo.liveFooInstances);
}
}
class Program
{
static void Main(string[] args)
{
foo aFoo = new foo();
aFoo.TestMethod();
//Console.WriteLine(aFoo.ToString()); // if this line is uncommented TestMethod will never return
}
}
if run with a debug build, with the debugger attached, or with the specified line uncommented TestMethod will never return. But running without a debugger attached TestMethod will return.
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.