Reputation:
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?
Upvotes: 18
Views: 24620
Reputation: 179
the other way is passing caFree to Action of formonclose
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
end
Upvotes: 0
Reputation: 613013
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.
Upvotes: 6
Reputation: 108963
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.
Upvotes: 5
Reputation: 25678
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."
Upvotes: 16
Reputation: 84550
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.
Upvotes: 10