Most of my posts on here have been about technical subjects, geared towards moderate-to-advanced Delphi coders. This one’s to help out the beginners who are still learning the ropes. I’d like it to be something that people can send new users to from StackOverflow or other sites if they’re having trouble figuring out how to clean up their memory properly.
I’ve never really understood why people find memory management difficult. Maybe I just “get it” for some reason, but it’s never seemed all that arcane or complex to me. In all my time working with Delphi, I’ve only run into one truly difficult memory management scenario, and it’s something that most people won’t ever have to deal with: sharing global interface references across package boundaries. If you do that wrong, you’re likely to run into some very strange errors at program shutdown that are hard to debug.
But people keep asking questions about the basics of what to free and how to free it on StackOverflow, and from answering them and analyzing the questions and the answers, it seems to me that the entirety of memory management can be boiled down to one single principle.
The Single Ownership Principle:
Each variable in your code has one and only one owner, and it’s the responsibility of that owner to free the variable’s memory when it is no longer needed.
Remember that principle. Internalize it. It will make your life as a coder easier. The question, then, is what the owner is. How do you identify it? And the answer is, that depends on the variable.
From a memory-management perspective, there are three classes of variables in Delphi, and you really only have to worry about one of them. Let’s take care of the hard one first, and then the easy cases:
Objects and pointer references: If you create an object, (a normal one that doesn’t have interfaces,) memory gets allocated to store its data in, and this memory needs to be freed. The same goes if you allocate memory for a pointer with New or GetMem. Your pointer or object reference is carrying active memory that needs to be released by its owner. But who owns it?
That depends on where the memory is. If it’s a field on an object, which you set up in the constructor or someplace later on, then the object owns it and you need to free it in the destructor. If you create it locally in a procedure or function and use it locally, you should free it in the code when you’re done with it. Try/finally blocks help to get this right. The other case is creating an object locally and handing it off to another object, such as a TObjectList. If you do this, then the other object becomes the owner. A lot of container classes have an OwnsObjects option to make sure they’ll free objects that they hold automatically once the container is freed.
It’s possible to pass an object around from one owner to another, but the more times you do this, the better chance you have of getting confused as to who the owner is and when it needs to be freed. You usually won’t have to do it more than once for any given object. If you do, be careful with what you’re doing, and check to make sure that there isn’t a simpler way to accomplish your task. This is why a lot of people don’t like to use functions that create and return a new object. For example, if you need a new list of a bunch of strings, instead of making a function that creates and returns a TStringList, make a function that accepts a TStringList as a parameter and fills it. Then you don’t have the ownership being passed around.
Now, for the simple cases:
Stack data: Numbers, characters, static arrays, records, and pointers of all kinds are allocated on the stack when they’re local variables, or as part of the object’s memory space when they’re part of an object. You don’t need to do anything at all to clean them up. The compiler takes care of it for you. If you have an array of objects, or a pointer that points to memory that you’ve allocated, then those have to be cleaned up, but the array itself or the pointer variable get taken care of by the compiler.
The same goes for records. If you have a record that owns an object reference, you need to clean it up before you’re done with the record. But since records don’t have destructors and get cleaned up automatically, this one can slip by you. The best solution is, don’t use records that own objects if you can possibly avoid it. If you find yourself doing that, it’s probably better to turn it into an object. Records are best used for holding groups of simple variables, like a TRect or a TPoint.
Compiler-managed variables: Strings, dynamic arrays, interfaces and variants aren’t stack data and need to be cleaned up, but the compiler creates code to take care of it for you. If you ever see a string in a memory leak report from FastMM, it doesn’t mean you forgot to clean up a string somewhere. You can’t forget that, since you can’t do it manually in the first place. What it means is that you forgot to clean up the string’s owner, which is probably an object.
The only tricky point here is with interfaces. They are managed by reference counting, which is exactly what it sounds like. The compiler has some special code to keep a count of how many things are holding a reference to the interface, and when that drops to zero, it gets freed. But this means that if you have two interfaces which both reference each other, then neither of them can fall to zero and they’ll both end up leaking. If you ever get into this situation, you probably need to change the design of the interfaces.
About FreeAndNil: Any discussion of memory management in Delphi is going to run into the subject of FreeAndNil sooner or later. Some people will say it makes you more safe than using Free, and you need to use it everywhere. Some people call it a mess that creates problems, and you shouldn’t ever use it. An then some people say to use it in moderation. But what does it do, and why do you want (0r not want) to use it?
Well, what does FreeAndNil do that Free doesn’t? That’s easy. It sets the object reference to nil as well. So then, if you want a rational answer, the question to ask is, why would you want to set an object reference to nil once you’re done with it? And there’s only one good reason to ever do that: If you want to reuse the variable later. There are some times when you’ll have an object that may or may not be initialized. If it’s not, then the variable will be nil, and if you find it’s nil, then you create it before using it. This is a pretty common pattern. It’s called “lazy creation”. But every once in a while, you want to use lazy creation on an object, then destroy it and create it again. This is when FreeAndNil comes in handy.
For example, in my TURBU Editor project for building console-style RPGs, each project can contain many maps. They’re stored in the map engine with an array of map objects. You can only have one open in the editor at a time, but if you’ve been working on editing several different maps, it will keep them in memory if you switch between maps. It takes about half a second to load a map from the disc. That’s pretty fast, but if you have hundreds of maps, you don’t want to wait a few minutes for them all to load. That’s where lazy creation comes in handy. It only loads a map if the user asks for it. Otherwise, its slot in the map array is nil. But if you finish with a map and you don’t have any unsaved changes, it will free the map to keep memory usage down. I use FreeAndNil here so that the next time it checks to see if the map is loaded, it will find a nil and know to load it again, instead of trying to access a freed variable.
But if you don’t need to free a variable and then reuse it, it’s probably better not to use FreeAndNil. It’s not typesafe; you can pass things other than objects to it. If you do this, one of three things will happen. Most of the time, you’ll get an access violation when it tries to call Destroy on your non-object. This is good. It immediately drops you to the debugger (assuming you catch this during testing) and with a bit of checking in the call stack you’ll hopefully see what you did wrong.
If you’re unlucky, the bytes might line up in just the right way that you don’t get an access violation. If you’re mildly unlucky, DEP might kill your program. If you’re very unlucky, you’ll end up in a valid routine, which will either raise an exception almost immediately and leave you wondering how in the world you ended up here, or silently corrupt data and cause trouble for you further down the line, without a stack trace to lead you back to the source of the problem. This is why I think it’s better not to use FreeAndNil unless you have to.
About leak tracing: No matter how careful you are, eventually you’re going to slip up and forget to free something. Thankfully, the FastMM memory manager has built-in functionality for telling you when you’re leaking memory. If you’re using Delphi 2006 or later, FastMM is included in your programs by default. If not, you can still use it. Just download it here. (And you should. Even without the leak tracking, it’s much better than the old Borland memory manager.) Put the following line in your DPR:
ReportMemoryLeaksOnShutdown := DebugHook <> 0;
This means that if the DebugHook variable is set, which only happens when the Delphi debugger is attached to the program, FastMM will give you a memory leak report when you quit. If you’ve missed something, it’ll let you know what objects you forgot to free and how many of them you missed. If you need more information, follow the instructions on setting up Full Debug Mode. You’ll need FastMM_FullDebugMode.dll, which doesn’t come with Delphi but it’s part of the free download. Then the memory leak tracker will give you a very detailed report in a text file. The most important thing it will give you is a stack trace telling you when each variable was created.
Here’s the trick, though. If you see a memory leak report that says you leaked 500 objects of type TMyDataObject and one object of type TObjectList, you might intuitively think that the massive leakage of TMyDataObject objects are the important thing and ignore the TObjectList. Go after the biggest problem first, right?
Wrong. Object ownership graphs tends to look a lot like trees, and like a real life tree, if you cut it down at the trunk, all the branches will fall too. If you see something like this, it’s very likely that that TObjectList owns all those TMyDatObject instances, and you just forgot to free it. So when you’re tracking down a complex set of memory leaks, start from class with the smallest number of leaked objects. Make sure that gets freed, then run again and see how much that cuts your leak report down by.
Well, that’s pretty much it. That’s not everything there is to know about Delphi memory management, but it’s about 90% of it, and the rest is pretty advanced stuff you aren’t likely to run into until you become experienced enough to work it out on your own. Oh, and if you’re ever sharing global interface references across package boundaries, make sure to set all the interface references to nil before the packages start to finalize. It’ll save you a lot of grief.