The example below shows where memory leaks can cause a problem (copy and paste into LinqPad):
void Main() { //subscriber subscribes to publisher event PublisherSubscriberExample(true); //subscriber does NOT subscribes to publisher event PublisherSubscriberExample(false); } void PublisherSubscriberExample(bool subscribeToEvents) { String.Format("SubscribeToEvents: {0}", subscribeToEvents).Dump(); Publisher pub = new Publisher(); Subscriber sub = new Subscriber(pub, subscribeToEvents); WeakReference refPub = new WeakReference(pub); WeakReference refSub = new WeakReference(sub); //print publisher and subscriber object state pre dispose String.Format("Pub: {0}", refPub.IsAlive).Dump(); String.Format("Sub: {0}", refSub.IsAlive).Dump(); //dispose of the subscriber object sub = null; //force garbage collection for the subscriber object GC.Collect(); //print publisher and subscriber object state post dispose String.Format("Pub: {0}", refPub.IsAlive).Dump(); String.Format("Sub: {0}", refSub.IsAlive).Dump(); } class Publisher { public event EventHandler PublisherEvent; public Publisher() {} } class Subscriber { Publisher _publisher; public Subscriber(Publisher publisher, bool subscribeToEvent) { _publisher = publisher; if (subscribeToEvent) _publisher.PublisherEvent += PublisherEvent; } void PublisherEvent(object sender, EventArgs e) { } }We have a Subscriber and Publisher class; the Subscriber takes a Publisher instance and subscribes to an event. When the Subscriber instance goes out of scope (i.e. disposed of and requested for garbage collection), the Publisher instance still maintains a reference to the Subscriber as the Subscriber has NOT explicitly unsubscribed from its original subscription. Whilst the Publisher instance is still in scope so will the Subscriber instance.
To get round this issue it is therefore good practice to implement IDisposable on the Subscriber class so that the event can be unsubscribed from upon disposing of the object:
class Subscriber : IDisposable { Publisher _publisher; public Subscriber (Publisher publisher, bool subscribeToEvent) { _publisher = publisher; if (subscribeToEvent) _publisher.PublisherEvent += PublisherEvent; } public void Dispose() { //free managed resources this.Dispose(true); } void Dispose(bool disposing) { if (disposing) { //free managed resources _publisher.PublisherEvent -= PublisherEvent; } } void PublisherEvent(object sender, EventArgs e) { } }You would then call Dispose on objects which expose this method instead of setting the reference to NULL.
No comments:
Post a Comment