Back when I was a TA, I found that a few people had a very curious misconception. In C++, they thought, if you never deleted an object, that object would never ever get freed until you restarted your computer. Basically, that a memory leak is memory that is lost and gone forever (for all intents and purposes).
This isn’t true, of course (at least on every operating system that has some form of memory protection) – when your application exits, the operating system reclaims all of the pages of memory that your application ever requested. In a very general way, it works like an autorelease pool (kinda like Objective C) – when your application exits, it is implicitly telling the operating system that it is done with all of its memory, and the operating system will then reuse the pages whenever it needs them.
Memory management is an area that almost every C++ programmers struggles with at some point or another, especially with the extremely negative connotation that “memory leak” holds. In order to beat “correct” memory management into you, then, your professors beat into you that every new must have a matching delete. Every malloc must have a matching free. Every AddRef must have a Release. Every operation that grabs a resource must let go of that resource when it is done.
And this is all well and good and true – you should always clean up whatever you dirty up. You can really never go “wrong” cleaning up your own messes. Well, unless you count performance :)
Imagine that on your first day of work, in addition to receiving a desk, chair, and computer, you are also given a hand vacuum, with instructions to vacuum out your office every evening. You are also told that, in addition to you getting a tiny hand vac, the company also employs a janitorial staff that will be vacuuming your floor nightly with a nice, big, real-person vacuum.
That’s like short-bus stoopid, you think. Why should I vacuum my office if the cleaning crew is going to do it every day anyways?
And you are exactly right – it is wasted effort for you to perform all these actions yourself, especially since they are more efficient at it.
The analogy is pretty (painfully, I’m sure) obvious – the OS is the janitorial crew that comes in and cleans up after your mess when the program exits, so in cases where you are just going to clean up your memory on exit, why not just let the OS take care of it?
Now, you have to be careful – this only applies to objects whose lifetimes (or ends of lifetimes) are identical to that of the program. Say, for example, the underlying data for the menu bar in your GUI application, or, in an application like Visual Studio, the software services that run for the duration of the applications. If all you are doing, on exit, is freeing the memory for these things, you are making your application’s shutdown more painful when it doesn’t need to be.
That, also, is one of the great advantages of garbage collection – allocating and freeing memory, piece by piece, is really, annoyingly slow. With a GC (or, to a lesser extent, with Objective C’s autorelease pool), you are letting some other piece of logic make some much smarter optimizations about memory – freeing it all at the same time, re-using it more intelligently, and, best of all, letting it not free it until it is most efficient (which, in the case of shutdown, could be never).
The other important thing is that this really only applies to freeing memory – your object may really need some type of special “shutdown” logic, like closing off a network/database connection, or writing some closing information to a log, or saving the state of something. In those cases, you might really need to have logic run when you are deleted/collected, a la finalizers or registering logic for when the application does exit. But, as it turns out, those cases are likely the minority, especially when you count objects irrespective of size.
The moral of this story is simple – if you are freeing memory on exit, you are wasting the user’s time.