I work on a project where there is a huge number of objects being instanced by a few classes that stay in memory for the lifetime of the application. There are a lot of memory leaks being caused with OutOfMemoryExceptions being thrown every now and again. It seems like after the instantiated objects ago out of scope, they are not being garbage collected.
I have isolated the problem to being mostly about the event handlers that are attached to the long-living object that are never detached, thus causing the long-living object to still have a reference to the out of scope objects, which then will never be garbage collected.
The solution that has been proposed by my colleagues is as follows: Implement IDisposable on all classes, across the board and in the Dispose method, null all the references in your objects and detach from all event that you attached to.
I believe this is a really really bad idea. Firstly because it’s ‘overkill’ since the problem can be mostly solved by fixing a few problem areas and secondly because the purpose of IDisposable is to release any unmanaged resources your objects control, not because you don’t trust the garbage collector. So far my arguments have fallen on deaf ears. How can I convince them that this is futile?
By coincidence I just posted this comment elsewhere:
And you say:
Now, the
+=and-=operators on an event are effectively a pair of functions that you have to call an equal number of times with corresponding arguments (the event/handler pair being the corresponding arguments).Therefore they constitute a resource. And as they are not dealt with (or “managed”) by the GC for you, it can be helpful to think of them as just another kind of unmanaged resource. As Jon Skeet points out in the comments, unmanaged usually has a specific meaning, but in the context of
IDisposableI think it’s helpful to broaden it to include anything resource-like that has to be “torn down” after it has been “built up”.So event detaching is a very good candidate for handling with
IDisposable.Of course, you need to call
Disposesomewhere, and you don’t need to implement it on every single object (just those with event relationships that need management).Also, bear in mind that if a pair of objects are connected by an event, and you “cast them adrift”, by losing all references to them in all other objects, they don’t keep each other alive. GC doesn’t use reference counting. Once an object (or island of objects) is unreachable, it is up for being collected.
You only have to worry about objects enlisted as event handlers with events on objects that live a long time. e.g. a static event such as
AppDomain.UnhandledException, or events on your application’s main window.