In olden times, when I did C and C++ development, memory leaks were a common thing. From time to time I still wake up from nightmares in which I debug, trace and try to locate and plug memory leaks (of course, as this is nightmare, I fail to do either, or it wouldn’t be a nightmare). Thankfully, in unmanaged code, memory leaks can be spotted in a debugger (or a plain old segmentation fault) and if you are paying attention, you can plug the leak right after you made it.
Then came Java and .NET, JIT compilers and a great thing called garbage collector. And we were told, we can forget about memory allocation, deallocation and pointers as a whole. We now have a garbage collector that will do this for us. And it does, if you know how to use it. But now, we became so reliant on garbage collector, that we just assume it will do everything for us. These days, it seems developers think that just because application is written in .NET it will somehow obtain immunity to memory leaks.
Boy do I have news for you! It won’t. Just last week, I spent most of my time debugging, tracing and removing a memory leak that caused otherwise stable windows service to throw OutOfMemory exception in 90 minutes. As .NET code is managed, tracing the leak gets tricky and the fact that code was not mine only made it worse.
If you write a one-off trivial application, memory leaks are nothing to worry about, as garbage collector will release the memory, when application is closed. And since application runs only short period of time, unless you do something completely moronic, you are fine and users might not even notice.
But, as soon as you start writing serious applications and applications that have to run 24/7 (e.g. Windows Service), things change. Any serious application has to assume, that, if object is not disposed correctly, it will accumulate in memory until the application is closed or it crashes. Preferably on Friday at 3pm when you are about to head for your well deserved vacation.
So what can you do? Personally, I stick to one simple rule that removes a risk of good portion of possible memory leaks. Any object that implements IDisposable interface has to be either encapsulated in using statement or disposed explicitly. Preferably in finally statement of try-catch block. It also helps to go the extra mile and remove reference to objects used as soon as possible and thus allow garbage collector to do its job properly.
And our memory leak? With great cooperation from our customer and some good fortune, we obtained enough information to locate the leak. It was caused by opening a Stream object about 1 million times without ever closing it.