Question

I always try to create my Applications with memory usage in mind, if you dont need it then don't create it is the way I look at it.

Anyway, take the following as an example:

Form2:= TForm2.Create(nil);
try
  Form2.ShowModal;
finally
  Form2.FreeOnRelease;
end;

I actually think Form2.Destroy is probably the better option, which brings me to my question..

What is the difference between calling:

Form2.Destroy;
Form2.Free;
Form2.FreeOnRelease;

They all do the same or similar job, unless I am missing something.

And also when should any of the above be used? Obviously when freeing an Object I understand that, but in some situations is Destroy better suited than Free for example?

Was it helpful?

Solution

Form2:= TForm2.Create(nil);

This is a code-smell, because Form2 is probably the global, IDE-generated variable that would normally hold an IDE-created TForm2. You most likely want to use a local variable, and one with a better name. This is not necessary an error, just a code-smell.

Form2.Destroy vs Form2.Free

Use Form2.Free, because it calls Destroy anyway. You can CTRL+Click on the name (Free) to see it's implementation. Essentially Free calls Destroy if Self is not nil.

Form2.FreeOnRelease

As the documentation says, "It should not be necessary to call FreeOnRelease directly."

OTHER TIPS

I've never actually heard of FreeOnRelease before. A quick Google search turned up the reason why. From the official documentation:

FreeOnRelease is called when an interface implemented by the component is released. FreeOnRelease is used internally and calls the corresponding interface method. It should not be necessary to call FreeOnRelease directly.

As for Free vs. Destroy, Free is a safety feature. It's basically implemented as if self <> nil then self.Destroy;, and it was created to make constructors and destructors safe to use. Here's the basic idea:

If you're constructing an object and an unhandled exception is raised, the destructor gets called. If your object contains other objects, they may or may not have been created yet by the time the error occurred, so you can't just try to call Destroy on all of them. But you need a way to make sure that the ones that have been created do get destroyed.

Since Delphi zeros out the address space of an object before calling the constructor, anything that hasn't been created yet is guaranteed to be nil at this point. So you could say if FSubObject <> nil then FSubObject.Destroy again and again for all the sub-objects, (and if you forget that you're going to get access violations,) or you can use the Free method, which does it for you. (This is a huge improvement over C++, where the memory space is not zeroed before the constructor is called, which requires you to wrap all your sub-objects in smart pointers and use RAII to maintain exception safety!)

It's useful in other places as well, and there's really no reason not to use it. I've never noticed that Free imposes any measurable performance penalty, and it improves the safety of your code, so it's a good idea to use it in all cases.

Having said that, when dealing with forms specifically, there's an additional variable to factor into the equation: the Windows message queue. You don't know if there are still pending messages for the form you're about to free, so it's not always safe to call Free on a form. For that, there's the Release method. It posts a message to the queue that causes the form to free itself once it's got no more messages to handle, so it's generally the best way to free a form you no longer need.

The canonical form is:

Form := TMyForm.Create(nil);
try
  Form.ShowModal;
finally
  Form.Free;
end;

Never call Destroy, always call Free instead.

FreeOnRelease is a total red herring. Sometimes, if there are queued messages destined for your form or its children, then you might elect to call Release although often that's indicative of design problems.

The idiomatic usage is

procedure SomeProc;
var
  frm: TForm2;
begin
  frm := TForm2.Create(nil);
  try
    frm.ShowModal;
  finally
    frm.Free;
  end;
end;

or, unless you hate the with construct,

with TForm2.Create(nil) do
  try
    ShowModal;
  finally
    Free;
  end;

You should never call Destroy, according to the documentation. In fact, Free is exactly equivalent to if Self <> nil then Destroy;. That is, it is a 'safe' version of Destroy. It doesn't crash totally if the pointer happens to be nil. [To test this, add a private field FBitmap: TBitmap to your form class, and then OnCreate (for instance), try FBitmap.Free vs. FBitmap.Destroy.]

If you create the form using the approach above, Free is perfectly safe, unless you do some strange things in the form class.

However, if you use CreateForm(TForm2, Form2) to create the form and store the form object in the global instance variable Form2 and you don't free it immediately [for instance, if you want the window to stick around next to the main form in a non-modal way for a few minutes], you should probably use Release instead of Free. From the documentation,

Release does not destroy the form until all event handlers of the form and event handlers of components on the form have finished executing. Release also guarantees that all messages in the form's event queue are processed before the form is released. Any event handlers for the form or its children should use Release instead of Free (Delphi) or delete (C++). Failing to do so can cause a memory access error.

FreeOnRelease has nothing in particular do to with forms. From the docs:

It should not be necessary to call FreeOnRelease directly.

the other way is passing caFree to Action of formonclose

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top