tags:

views:

118

answers:

5

Hi Guys,

Too many times we find out that strange behavior / performance issues in the system are caused by "dead" events - events that invoked on freed objects. It looks like you need to always release (-=) existing event before registering a new one. This looks like best practice but how can we detect such a situation in existing code? Is there a tool which can spot a problem in the code relating to freeing events?

Hope my question was clear,

Thanks

Adi Barda

A: 

The simplest way to avoid this situation is to use the compiler. If you only want to allow one delegate at a time, don't declare it as an event (which is inherently multicast), but as a plain delegate.

In other words, rather than having:

public event MyDelegateType MyEvent;

Use the following:

public MyDelegateType MyEvent;

Then the callers, rather than composing the delegate with +=, simply assign to it with =, implicitly removing the previous delegate.

JSBangs
problem with delegates that they are not secure! anyone from the outside can invoke your (event) delegate. events are much more secured - only their owner can invoke them.
Adi Barda
You can solve that by adding an accessor that is private get; public set; Yes, that's a weird pattern, but it fixes your problem.
JSBangs
A: 

Have a look at this article, which discusses the situation you have, and provides some links to some tools that can profile your code.

http://msdn.microsoft.com/en-us/library/ee658248.aspx

sgrassie
A: 

As always, be explicit and forget that GC exists (irony). Do the -= and sleep well.

Alternative, a hack, WeakReferences..

rama-jka toti
This isn't necessarily good advice. Forgetting to unsubscribe from events is a common source of memory issues in .NET programs.
Reed Copsey
Which is stated above, 'to forget GC exists' and to be explicit. Sleep well too. Furthermore, WeaKReferences is specified as 'hack', despite the fact it is more and more in use by your favourite libraries.. Irony is that memory should be managed by the GC and it pretty much fails so miserably at a simple circular reference leaving a root alive..
rama-jka toti
+2  A: 

You could use event accessors to keep track of when an event is registered or unregistered.

Konamiman
A: 

It looks like you need to always release (-=) existing event before registering a new one.

There is a flaw in this. You do not need to release an existing event before registering a new handler - there are many times when you want to have more than one object subscribing to a single event source. This is a common, and very useful, practice.

The issue is more commonly not unsubscribing to an event when you are finished listening to it. The GC will clean this up when the source and listener both become unrooted, but until then, it can prevent certain objects from being released.

The general rule of thumb I follow is this:

If you can easily track when you want to subscribe and unsubscribe (ie: you have a fixed lifetime, and its shorter than the lifetime of the event source), you should subscribe and unsubscribe yourself appropriately.

If you cannot track when you should unsubscribe, for example, if the lifetime of your class or the source object is indeterminate for some reason, or the source may need to be disposed prior to when you will be disposed, use the WeakEvent pattern.

Reed Copsey
The problem with this is that too many times it is too late (like poster realised). Thus you have a situation where you cannot easily track and have to resort to a Weak hack. The only proper way is to be explicit and utilise the Disposable concept. Simple lifetime management, not amortising and causing even more pain down the road. All of which leads to a catastrophic leak and OutOfMemory exceptions on any decent scale app, yet the GC sits idle, takes ages to catch this rather simple problem it is meant to avoid epsecially with many VM implementers shouting how reference-counting was flawed.
rama-jka toti
And there you have it, timely break of circular references was supposed to be one of its strengths but it shows a major strength in swallowing ram or throwing out-of-memory dump if you ask me.. The example you mention as flaw because there are more than one subscriber seems pretty artificial; or at least I cannot see the problem in that scenario at all.
rama-jka toti
I really disagree with this sentiment. IDisposable is very useful here, in many cases, but you should be able to track references well. If you can't, WeakEvents are a very useful for exactly this scenario, and are not a hack. Multiple subscribers is not artificial - it's very common. Any time you're trying to subscribe to things like system events, you will frequently have multiple subscribers.
Reed Copsey