I've an application where I'm not able to remove event handlers because I don't know when the last reference will be freed.
My application contains a PropertyChanged event source that is put into a container class that also implements INotifyPropertyChanged. This hierarchy contains more than 6 levels. Each instance of a level could be placed into multiple other instances. That's
the reason why I couldn't determine when to free those instances.
The instances on the lowest level will live for the whole application runtime. This causes that all other instances will not be freed and I got a memory leak.
To avoid this event driven memory leak I tried to use WeakEventManager(TEventSource, TEventArgs). This class is only available in .Net 4.5 and because of compatibility to existing hardware I’ve to use .Net 4.0.
In .Net 4.0 is a PropertyChangedEventManager available that should do the same for INotifyPropertyChanged.
My classes are freed correctly.
But there is still a memory leak.
I simplified my application to the following code that produces a memory leak:
// This code will force the memory leak while (true) { var eventSource = new StateChangedEventSource(); var eventReceiver = new StateChangedEventReceiver(); PropertyChangedEventManager.AddListener(eventSource, eventReceiver, string.Empty); } public class EventSource : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; } public class EventReceiver : IWeakEventListener { public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { return true; } }
Yes I know there is no RemoveListener call. I couldn’t determine when an instance is never used and could be freed. If I knew that I could use normal event registration and deregistration. In that case I don’t have to use the PropertyChangedEventManager.
What is the problem of my sample code? Why does it produce a memory leak?
I used JetBrains Memory Profiler to detect my memory leak. I could reduce the memory consumption a lot by using the PropertyChangedEventManager but there's still a memory leak left that could be simply reproduced using the sample code of this question.