Jump to content
Paul Dardeau

Guidance on FreeAndNil for Delphi noob

Recommended Posts

Embarcadero hosted a youtube livestream the other day with MVPs. It was a debate on use of FreeAndNil. Being new to Delphi, I don't have any historical baggage (well, I do; but not on this particular topic) or preconceived notions of how it should be done. I was disappointed that the video didn't at least include a "if you're brand new to delphi, here's our recommendations on the use of FreeAndNil". Having said all that, can you suggest some best practices for someone who's new to Delphi on good use of FreeAndNil?

Share this post


Link to post
2 hours ago, Paul Dardeau said:

can you suggest some best practices for someone who's new to Delphi on good use of FreeAndNil?

Use it ONLY when you NEED it.

 

When freeing an object that is pointed at by a given pointer variable, and that variable may be used again later, then nil'ing that variable makes sense, as future code will be sensitive to what the variable is (or is not) pointing at.

 

But, if the pointer variable is not going to be used after freeing the object, then there is simply no point is nil'ing the variable.

  • Like 3

Share this post


Link to post

As usual, there is no correct answer. Just opinions/options.

 

Option 1: Just use FreeAndNil all the time.  This way, you don't have to think about it, you can code it up in the Delphi IDE auto-complete stuff (and other tools like MMX). It is doing a bit of extra work, and calling an extra method, but you would need to doctor up some very contrived examples to have the speed penalty from FreeAndNil make any kind of impact on your code performance.

 

Option 2: Use FreeAndNil if you free objects in the middle of a method when there is code executing afterwards and you are scared you may accidentally use the freed variable. Also use FreeAndNil in explicit cases where a valid state of an object variable is NIL. If you free objects as the last few lines of a method (or in a destructor) dont use FreeAndNil and rejoice at the nanoseconds of processing speed you have saved compared to option 1

 

Option 3: never use FreeAndNil. If you use FastMM there is an option on it to catch the use of freed memory. That option does slow down things quite a bit, but it works. That way, even if you reuse a freed object variable, FASTMM will throw an exception. Or, if you dont use FastMM then simply don't make coding errors 🙂 Seriously though, it can take ages to find errors stemming from using freed memory if you dont have FastMM debug mode on, and all the nanoseconds in the world saved from not using FreeAndNil is not worth the hours it will take you to find the bug. 

Edited by Dave Novo
  • Like 1

Share this post


Link to post

It is very likely that whatever decision you make now, you will adjust as you get more experience.  This is a topic without a true correct answer... it simply depends.  

 

If you want to be strict and always follow a single rule - then use FreeAndNill all the time.  After a while, you will wonder why you are doing that and you can revisit after you have some code in place.

 

For me, I only rarely use FreeAndNil - only when it is part of the normal logic that instance again could/will be read in the future and that I will need to know it's correct state.  (For example, treat nil as a special 'done' or 'not yet started' type flag.)

  • Like 1

Share this post


Link to post

I always use FreeAndNil, even if it is the last line of a method. Why? Because my code evolve, I can copy/paste it somewhere, add line,... If the object variable (Actually a pointer btw) is nullified, I'm sure I'll get and exception if I forgot I can no more use that object reference. The impact on performance is nearly null.

But all rules can be ignored sometimes...

  • Like 1

Share this post


Link to post

FreeAndNil is something that you will need to use rarely (it might depend on the kind of code you are writing).  In places where your code needs it logically it will be obvious that you need it and everywhere else you can use Free.

 

The point that FreeAndNil can help you avoid errors and mistakes is full of holes. First, simple access after Free is usually easy to catch either by looking at the code (local variables) or by using memory manager in debug mode or other specialized tools. Next, FreeAndNil nils only single reference to the object instance. If you have multiple ones you will still have to deal with dangling pointers and you will need to learn how to use previously mentioned tools. Most of the problems with memory management in Delphi are caused by having multiple references to single manually managed object instance as such code is more complex. This is exactly the place where FreeAndNil cannot help you, but where using it will give you false sense of security.

 

Another reason against using it everywhere, is that it obscures the code intent. Logically, FreeAndNil means that variable will be reused and this is important information. If you use it everywhere, you will have mush harder time reading the code and understanding its intent. And code which is harder to understand is also harder to maintain in the long run. Of course, that can be solved with comments, but then you will have to use them everywhere or you will never know whether some comment is missing somewhere.

 

Manual memory management requires some discipline. thinking about the code you are writing enforces the discipline and makes you a better programmer. Taking the "easy" path where you will slap FreeAndNill everywhere just so you can avoid accidental mistakes and thinking is going to cost you at some point. Many existing codebases where it is used everywhere cannot be easily migrated to not using it as it can be hard to determine where it is needed and where it is not (except for local variables) and they need to continue using it indefinitely in all places, as the only thing worse than using FreeAndNil everywhere is using it randomly. Consistence in code is the king.  

 

In my codebase I have less than 50 places where I am using FreeAndNil (I cannot tell the exact amount as I have many smaller projects and it is not easy searching through them as some contain fixed VCL code which uses FreeAndAil a lot, so I cannot easily count usage in my files only)

 

One of the advantages of being a new Delphi developer is that you don't have a lot of existing code where FreeAndNil was used in places where it is not needed :classic_smile: and now is the right time for you to decide whether you want to pollute your code with FreeAndNil and stick with it forever or not.

  • Like 1

Share this post


Link to post

Thank you all for the very helpful comments. I really appreciate it!

 

I don't have a single FreeAndNil in my project because I didn't know about it prior to the youtube livestream. I do have many places in my code where an object variable will have long lifetimes and will need to be reused. In those cases, I have this:

 

FMyObject.Free;

FMyObject := nil;

 

Should I go back and change those 2 statements to the single call FreeAndNil?

 

FreeAndNil(FMyObject);

Share this post


Link to post
50 minutes ago, Paul Dardeau said:

FMyObject.Free;

FMyObject := nil;

 

Should I go back and change those 2 statements to the single call FreeAndNil?

You can keep this code. It is equivalent to FreeAndNil(FMyObject).

Do whatever you feel most readable for you.

Share this post


Link to post
4 hours ago, FPiette said:

You can keep this code. It is equivalent to FreeAndNil(FMyObject).

Equivalent, but not identical. Do keep in mind that there is one slight difference - FreeAndNil() nils the pointer before destroying the object. It is basically doing this:

var tmp := FMyObject;
FMyObject := nil;
tmp.Free;

So, if the call to Free() happened to raise an exception (ie, due to memory issues, or a bad pointer, etc), then the difference is whether FMyObject gets nilled or not. But in normal well-behaving code, this difference is negligible.

Edited by Remy Lebeau

Share this post


Link to post

Hi Paul,

 

As you can see, multiple excellent developers (I exclude myself from the list) have chimed in, with many different opinions, all of them valid. 

 

One point that you might not be aware of, is that when you free an object, the variable is still pointing to a location of memory on the heap. Until that memory is overwritten (as far as you should be concerned memory is randomly allocated and you cannot control/predict that) the object may behave fine. i.e. you can call methods on that freed object, and it will appear to work. Or, depending on what memory is overwritten, some of the methods on the object will appear to work, others will crash with an access violation or other error right away. The problem is that the crashes are quasi-random. Sometimes accessing the freed variable may crash right away, other times not.  In my experience, it crashes more reliably with a 64 bit compile than 32 bit compile.  This can be terribly hard to track/reproduce/fix if it only happens at a customers' site but does not crash on your computer, since for whatever reason, the memory is not reallocated on your computer in the same manner.

 

I would HIGHLY advocate learning how to use FastMM in debug mode and use that ALL THE TIME when developing code. You can turn it off when compiling for release. I

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×