Autounsubscribe events - c#

I have a static class which publishes a few events. So I have many different small classes that have different lifetimes that subscribe to this event.
I found out now that this leads to memory "leaks" because of the subscribing classes staying alive when they subscribed a longer-living event. I know that this is happening by using a memoryprofiler and I read about this problem.
I am not able to manually unsubscribe, as I might have hundreds of "clients" in a list. This list will just get cleared. So I can't (and don't want to) unsubscribe by hand.
I read that the "weak event pattern" might help here. Could someone please lead me to an "easy" way to implement this? All I found until now is either too simple to use in practice or too complicated to understand it in the beginning.
Or is there any "best practice" for this case?
Thanks in advance!
UPDATE:
Based on jbl's answer I found this (http://blogs.msdn.com/b/greg_schechter/archive/2004/05/27/143605.aspx) as a possible solution. Any comments here? It's rather old (2004), so there might be better solutions out there?

Never implemented something like that, but I would try (with a static class or a singleton, your choice) :
having the static class maintain a static collection of WeakReference to the client event handlers
the clients do not subscribe directly to the event. The static class exposes subscribe and unsubscribe methods which add/remove the handlers from the weak references collection
the static class is the only one subscribing directly to the event
upon event triggering, the static class enumerates the weak references collection and runs the handlers for the references which are still alive (removing the null ones)
Hope this will help

Best practice: always implement the Dispose pattern when a class subscribes to an event generated by an object not constructed by this class.
Then in the Dispose method remove the handler.
public NotificationServiceAccessor(ObjectWithEvent objectWithEvent)
{
_notificationService = new NotificationService();
_notificationService.StatusChanged += NotificationService_StatusChanged; // Local object, no Dipose
_objectWithEvent = objectWithEvent;
_objectWithEvent.AnEvent += AnEventHandler(); // Event that has to be disposed.
}
#region IDisposable Members
protected bool Disposed { get; private set; }
private void Dispose(bool disposing)
{
if (!this.Disposed)
{
this.InternalDispose(disposing);
}
this.Disposed = true;
}
protected virtual void InternalDispose(bool disposing)
{
if (disposing)
{
// Dispose here the event handlers
_objectWithEvent.AnEvent -= AnEventHandler()
}
// Dispose here only unmanaged objects
// Don’t use managed objects here because maybe
// they have been finalized already
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
~NotificationServiceAccessor()
{
this.Dispose(false);
}
#endregion

Related

Is it possible to detect when EventHandlers are added and disposed of outside of process?

I think the answer is NO but I thought of asking to see if it's possible at all
Scenario: I have a WPF application that uses a class with static events to subscribe interactions between different controls
Basically,
public class EventNotifier
{
public static event EventHandler<SomeEventArgs> EventTriggered;
public static void NotifyEventTriggered(object source, SomeEventArgs eventArgs)
{
if (EventTriggered!= null)
{
EventTriggered(source, eventArgs);
}
}
}
Then from some controls some methods get subscribed:
EventNotifier.EventTriggered+= new EventHandler<SomeEventArgs>(SomeMethodToReceiveEvent);
And from some other controls the events are triggered:
EventNotifier.NotifyEventTriggered(null, eventArgs);
This is all very straightforward. When the controls that subscribed their methods are disposed the events are disposed as well:
EventNotifier.EventTriggered-= new EventHandler<SomeEventArgs>(SomeMethodToReceiveEvent);
Given the nature of WPF that makes memory leaks rife where events are not unsubscribed correctly, until now I've had to manually test every control every time a leak was happening to ensure events were being disposed correctly. This is very time consuming
Some tools that analyze memory usage that I've used are completely incompetent at identifying the event that wasn't unsubscribed that was causing a memory leak
This is why I've been dreaming of creating my own tool to detect every time a method is subscribed to an event and also detect every time it's unsubscribed
I know I could do it in code using properties like:
private static event EventHandler<SomeEventArgs> eventTriggered
public static event EventHandler<SomeEventArgs> EventTriggered
{
add
{
eventTriggered-= value;
eventTriggered+= value;
//Add code here to keep track somewhere of event
}
remove
{
eventTriggered-= value;
//Add code here to keep track somewhere of event
}
}
But my dream tool would be one that is external to my application and hooks up to a process to monitor its events. Am I just dreaming or is this possible in any way?

Where to unsubscribe from events?

E.g. for a general type, which subscribe to some events in constructor:
class SomeType
{
public SomeType(...)
{
someEvent1 += ...
someEvent2 += ...
}
}
Where do I unsubscribe from events?
Finalizer?
IDisposable ?
Some method DontForgetToCallMeSoICanUnsubscribeFromEvents()?
Use weak events pattern?
I know it depends. In case of controls (wpf, winforms) there are some events what can be used to subscribe/unsubscribe like Loaded/Unloaded, HandleCreated/HandleDestroyed, etc. But what if parent is a simple object?
And some more specific example: nested ViewModels, where each level is a List<NextLevelVM>, at any level ViewModel can be deleted, does that means what each ViewModel must implement IDisposable (if e.g. it is the right way) where it call Dispose for each item in their list? I tried to use weak events, but that doesn't go well.
I've found a really good way to handle this issue is to create two methods in the page's code behind, that calls methods on your ViewModel to start/stop listening to events depending on whether it's visible or not.
Below I'm using the Appearing functions, but depending on the framework you're using it might be slightly different, but the strategy should work.
In Page class:
protected override void OnAppearing()
{
base.OnAppearing();
_myViewModel.StartListeningToEvents();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_myViewModel.StopListeningToEvents();
}
Then in my ViewModel, I actually subscribe to the events I require:
public void StartListeningToEvents()
{
SomeProperty.PropertyChanged += PropertyUpdated;
}
public void StopListeningToEvents()
{
SomeProperty.PropertyChanged -= PropertyUpdated;
}
void PropertyUpdated(object sender, PropertyChangedEventArgs e)
{
// do stuff
}
My example is for a property change event. But similar code should work for any event.
In this way you're guaranteed that your page is only listening to events when it's open, and you don't need to worry about disposing anything besides calling the one event when the page is no longer open.

Is it necessary to deregister event handler?

I see this piece of code written by someone else:
public class DynamicPageContent : IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
// it is necessary to
context.BeginRequest += new EventHandler(DynamicPageContent_BeginRequest);
}
//actual handler not pasting as it's meaningless for this question
}
As you can see the handler is registered but never deregistered. Wouldn't that create memory leak?
Event handling can create leaks but only under certain conditions.
The thing to watch out for is when the subscribing object has a larger lifespan than the publishing object.
The thing to watch out for is when the publishing object has a larger lifespan than the subscribing object.
In this case they appear to be the same object and then it is not necessary or useful to unsubscribe. That would only clutter your code.

Cleanly shutting down a DLL's Static events in a host I don't control

Does the following psuedo code accomplish my goal of cleaning up after myself when my DLL is being hosted by code I don't control?
More specifically, how do I clean up my objects created in my static constructor?
Do I need to suppress Finalize in the Disposable?
Am I guaranteed that the compiler or something will call IDisposable even if the Host doesn't?
Psuedo code:
public class MyDLL : SomeHostICantControl, IDisposable
{
public SpinLock MyDictionarySpinlock = new Spinlock; // approximate syntax
public static Dictionary<string, string> MyDictionary = null;
public static Timer MyCleanUpTimer = null;
public static MyDLL()
{
// Set up Cache Here ... how do I dispose of it?
MyDictionary = new Dictionary<string, string>();
// remove old data from the dictionary, use spinlock to sync writes
// or use concurrent dictionary in .NET 4
MyCleanUpTimer = new Timer(); // run every hour
}
// many instances will be created and disposed of. I have no control when or how often
public void MyDll()
{
this.MyHostEvent += New Event Handler....
}
//.. some event handler code here
public void Dispose()
{
this.MyHostEvent -= Event Handler.;
// Do I need to suppressFinalize here?
}
//~MyDll()
//{
// Is this the right place to clean up after my constuctor?
//}
}
Answering your questions in order:
Static fields exist for the lifetime of the application, as such they are "cleaned up" as a result of the application exiting (memory is reclaimed, files are closed etc.). You don't appear to be doing anything that might require explicit action to be taken to clean-up (e.g. flushing buffered data in a StreamWriter to file), but perhaps there are details missing in your code snippet.
You need to suppress finalize in your Dispose() method if your class has a finalizer (yours appears not to as it's commented out), or if someone can derive from your class and may introduce unmanaged resources that may need cleaning up. The latter applies here as your class is not marked sealed, so you should suppress finalize in Dispose().
The runtime will not call Dispose(), however it will call the finalizer if one is present. Note however that as you class instances don't appear to be using any unmanaged resources, a finalizer should not be required.

Is this a memory leak?

I have a class shown below. Server instance holds reference to listener instance. Listener holds reference to server instance through event delegate. Will this prevent GC from collecting server instance? If so, how to break this cycle? Should I implement IDisposable or override Finalize method or do something else?
public class Server
{
public Listener Listener { get; private set; }
public Server(Listener listener)
{
Listener = listener;
Listener.ClientChannelConnected += new EventHandler<ClientChannelConnectedArgs>(listener_ClientChannelConnected);
}
void listener_ClientChannelConnected(object sender, ClientChannelConnectedArgs e)
{
...
}
}
No. The .NET garbage collector is smart enough to resolve circular references.
Strangely, I found that this type of code consistently leaks in .net, and had to be careful to -= the event handler. It is true that the memory is released eventually, but in practice you want to clean up after yourself sooner than that.
Also, never ever use a lambda expression to handle an event, as you will never have a reference back to that object.
Read this article about memory leaks. Sometimes you should use -=.

Categories

Resources