Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Warum macht ein TForm.Close nicht NIL (https://www.delphipraxis.net/113468-warum-macht-ein-tform-close-nicht-nil.html)

Eurowig 8. Mai 2008 10:55


Warum macht ein TForm.Close nicht NIL
 
Hi.

Ein TForm.Close lässt eigentlich vermuten, dass das Objekt weg ist. Aber das ist es nicht immer, bzw. nicht sofort.

Delphi-Quellcode:
MyForm := TMyForm.Create(MainForm);
MyForm.Show;

...
...
MyForm.Close;

...
...
if MyForm <> NIL then
begin
  ShowMessage('Bin verwirrt. Warum bist du nicht NIL???')
end;
Damit ich auf NIL prüfen kann musste ich noch das 'Close' ergänzen

Delphi-Quellcode:
MyForm.Close;
FreeAndNil(MyForm);
Meine Frage: Ist das nun gut oder schlecht. Wenn ein Objekt auf NIL gesetzt wird was ist dann mit dem Speicher. Räumt Delphi trotzdem auf oder hab ich ein Speicherleck??
Ein 'TForm.Close' macht einen 'Release'. Bisher dachte ich damit wäre alles aus dem Speicher raus. Jetzt musste ich mit Erstaunen feststellen, dass dem nicht so ist.

Luckie 8. Mai 2008 10:59

Re: Herr 'Close' und Frau 'NIL'
 
So amüsant wie dein Threadtitel auch ist, er ist nicht sehr hilfreich, wenn es um die kurze Beschreibung deines Problems geht., Bitte ändere ihn in einen aussagekräftigen Titel.

Daniel 8. Mai 2008 11:00

Re: Herr 'Close' und Frau 'NIL'
 
Ein Glück, dass es nicht so ist.
Die Methode "Close" schließt das Fenster nur, aber es bleibt weiterhin vollständig im Speicher vorhanden und wartet nur darauf, mittels "Show()" wieder angezeigt zu werden. Bei Fenstern gelten leicht andere Spielregeln, hier solltest Du im Allgemeinen die Methode "Release" nehmen, um es aus dem Speicher zu entfernen. Das erlaubt dem Fenster, noch ein paar Aufräumarbeiten zu erledigen.

[edit]
... und dann natürlich das, was Luckie in Bezug auf den Thementitel sagte.
[/edit]

FAlter 8. Mai 2008 11:00

Re: Herr 'Close' und Frau 'NIL'
 
Hi,

das Objekt wird bei Close nicht unbedingt freigegeben, das hängt davon ab, was du im OnClose zurückgibst (Action = caFree --> Freigabe, ansonsten nicht).

Mit .Free oder FreeAndNil hingegen wird das Formularobjekt immer freigegeben, aber nur bei FreeAndNil wird es auch auf nil gesetzt, ansonsten verweist deine Variable immer noch an die Stelle, an der das Objekt vorher lag.

[edit] Wie wärs denn damit:

Delphi-Quellcode:
procedure ReleaseAndNil(var X: TCustomForm); //inline;
begin
  if Assigned(X) then
  begin
    X.Release;
    X := nil;
  end;
end;
[/edit]

Mfg
FAlter

Eurowig 8. Mai 2008 11:19

Re: Warum macht ein TForm.Close nicht NIL
 
Zitat:

Zitat von Daniel
... hier solltest Du im Allgemeinen die Methode "Release" nehmen, um es aus dem Speicher zu entfernen. Das erlaubt dem Fenster, noch ein paar Aufräumarbeiten zu erledigen.

Ein TForm.Close macht ein 'Release' oder etwa nicht ??

Auszug Forms.pas
Delphi-Quellcode:
procedure TCustomForm.Close;
var
  CloseAction: TCloseAction;
begin
  if fsModal in FFormState then
    ModalResult := mrCancel
  else
    if CloseQuery then
    begin
      if FormStyle = fsMDIChild then
        if biMinimize in BorderIcons then
          CloseAction := caMinimize else
          CloseAction := caNone
      else
        CloseAction := caHide;
      DoClose(CloseAction);
      if CloseAction <> caNone then
        if Application.MainForm = Self then Application.Terminate
        else if CloseAction = caHide then Hide
        else if CloseAction = caMinimize then WindowState := wsMinimized
        else Release;
    end;
end;

In der Delpi Hilfe steh:
Mit Release können Sie das Formular aus dem Speicher entfernen.

Dieser Info habe ich auch bisher Glauben gescheckt.

Sharky 8. Mai 2008 11:23

Re: Warum macht ein TForm.Close nicht NIL
 
Zitat:

Zitat von Eurowig
Ein TForm.Close macht ein 'Release' oder etwa nicht ??

Aber doch nur wenn im OnClose caFree als CloseAction angegeben ist.

Nuclear-Ping 8. Mai 2008 11:24

Re: Warum macht ein TForm.Close nicht NIL
 
Delphi-Referenz durchsuchenTCustomForm.OnClose
Zitat:

Zitat von Delphi Hilfe
Das Ereignis OnClose wird beim Schlieen des Formulars ausgelst.

type
TCloseAction = (caNone, caHide, caFree, caMinimize);

TCloseEvent = procedure(Sender: TObject; var Action: TCloseAction) of object;

property OnClose: TCloseEvent;

Beschreibung

Mit OnClose knnen Sie spezielle Verarbeitungen durchfhren, wenn das Formular geschlossen wird. Sie knnen in der zugehrigen Ereignisbehandlungsroutine beispielsweise prfen, ob in allen Feldern eines Dateneingabeformulars gltige Eingaben vorgenommen wurden.

Ein Formular wird geschlossen, nachdem die Methode Close aufgerufen oder im Systemmen die Option Schlieen gewhlt wurde.

Der Typ TCloseEvent zeigt auf eine Methode, die fr das Schlieen des Formulars zustndig ist. Der Parameter Action bestimmt, ob das Formular tatschlich geschlossen wird. Er kann die folgenden Werte annehmen:

Wert Bedeutung

caNone Das Formular darf nicht geschlossen werden, daher geschieht nichts.
caHide Das Formular wird nicht geschlossen, sondern lediglich verborgen. Die Anwendung kann nach wie vor auf das Formular zugreifen.
caFree Das Formular wird geschlossen und sein Speicher freigegeben.
caMinimize Das Formular wird nicht geschlossen, sondern als Symbol angezeigt. Bei untergeordneten MDI-Formularen ist dies die Standardeinstellung.

Enthlt bei einem untergeordneten MDI-Formular die Eigenschaft BorderIcons den Wert biMinimize, wird caMinimize als Standardaktion verwendet. Ist diese Eigenschaft nicht gesetzt, erhlt Action den Standardwert caNone, und beim Schlieen des Formulars werden keine speziellen Verarbeitungen durchgefhrt.

Bei einem untergeordneten SDI-Formular wird Action der Standardwert caHide zugewiesen.

Um das Formular in einer Ereignisbehandlungsroutine fr OnClose zu schlieen und freizugeben, setzen Sie Action auf caFree.

Hinweis: Beim Beenden der Anwendung tritt das Ereignis OnClose nur im Hauptformular, aber nicht in den untergeordneten Formularen auf.

(Umlaute sind beim Kopieren übers VNC verloren gegangen ...)

Eurowig 8. Mai 2008 11:25

Re: Warum macht ein TForm.Close nicht NIL
 
Ohhh neee :wall:

Jetzt hab ichs gesehen. Wenn ich im OnClose keine CloseAction definiere (z.B. caFree), macht es ein caHide.

Aber wie nun:
Delphi-Quellcode:
MyForm.Close;
MyForm.Release;
oder
Delphi-Quellcode:
MyForm.Close;
FreeAndNil(MYform)

Nuclear-Ping 8. Mai 2008 11:26

Re: Warum macht ein TForm.Close nicht NIL
 
Nur MyForm.Release für deine Zwecke.

mkinzler 8. Mai 2008 11:27

Re: Warum macht ein TForm.Close nicht NIL
 
Wird die Variable noch genutzt dann FreeAndNil() sonst MyForm.Free;

Muetze1 8. Mai 2008 11:29

Re: Warum macht ein TForm.Close nicht NIL
 
Zitat:

Zitat von Eurowig
In der Delpi Hilfe steh:
Mit Release können Sie das Formular aus dem Speicher entfernen.

Dieser Info habe ich auch bisher Glauben gescheckt.

Ja und? Das wird doch auch erfüllt.

Deine Variable ist nur eine Referenz auf den Speicher des Formulars. Du bist wirklich der Meinung, dass Delphi einen riesigen Verwaltungsaufwand treibt um im folgenden Beispiel alle diese Variablen auf NIL zu setzen, weil sie alle auf das eine Formular verweist?

Delphi-Quellcode:
var
  Form1, Form2, Form3, Form4, Form5, FormWhatever: TForm;
begin
  Form1 := TForm.Create(nil); // eine Instanz
  Form2 := Form1;
  Form3 := Form1;
  Form4 := Form1;
  Form5 := Form1;
  FormWhatever := Form1;

  // Nun zeigen alle diese Variablen auf dieses eine Formular.

  Form1.Release; // Formular freigeben

  // Nun ist der vom Formular belegte Speicher freigegeben. Aber alle Variablen von Form1 bis FormWhatever
  // enthalten aber immernoch die Adresse die das Formular hatte. Nur der Speicher an der Adresse ist wieder
  // verfügbar.

  // Irgendwelche Zugriffe auf Form1 bis FormWhatever sind tödlich!

  // Delphi müsste einen riesigen Verwaltungsaufwand treiben um alle Variablen auf NIL zu setzen. Schon allein
  // folgendes setzt (natürlich) nicht gleich alle Variablen auf nil:

  Form1 := nil;

  // Hiernach sind Form2 bis FormWhatever noch immer mit der alten Adresse gefüllt.
Anderes Beispiel:

Ein Freund von dir zieht um und hat eine neue Adresse. Du schreibst seine neue Adresse in dein Adressbuch, aber trotzdem sind nicht automatisch alle anderen Stellen wo die Adresse vermerkt wurde mit geändert: Outlook Buch, Telefon, etc.

Die Variablen die die Instanz der Form aufnehmen sind an unterschiedlicher Stelle im Speicher und sind jeder für sich. Diese Variablen verweisen nur an eine Stelle mit der Form Instanz.

Bernhard Geyer 8. Mai 2008 11:31

Re: Warum macht ein TForm.Close nicht NIL
 
Zitat:

Zitat von Muetze1
Deine Variable ist nur eine Referenz auf den Speicher des Formulars. Du bist wirklich der Meinung, dass Delphi einen riesigen Verwaltungsaufwand treibt um im folgenden Beispiel alle diese Variablen auf NIL zu setzen, weil sie alle auf das eine Formular verweist?

Das würde nur in einer managed Umgebung wie .NET oder Java gehen (und dort auch nicht für Ressourcen). Jedoch nachträglich ein Programm GC-Tauglich zu machen ist aufwendig.

hitzi 8. Mai 2008 12:08

Re: Warum macht ein TForm.Close nicht NIL
 
Zitat:

Zitat von mkinzler
Wird die Variable noch genutzt dann FreeAndNil() sonst MyForm.Free;

Was bringt mir ein MyForm.Free, wenn ich die Variable noch nutzen möchte? Wird mit Free nicht der Speicher der MyForm freigegeben und die noch in MyForm hinterlegte Speicheradresse verweist dann auf freigegeben Speicher?!

Ich hab bisher immer caFree oder eben FreeAndNil verwendet. Wenn ich nun Release statt FreeAndNil verwende, muss ich doch MyForm nach dem Release noch "nilen", oder? Wenn ja, gibt das dann keine unschönen Nebeneffekte, da Release laut Hilfe nicht wartet bis alles freigegeben wurde und so man theoretisch MyForm schon Nil zuweist bevor Release im Hintergrund überhaupt fertig ist.

Ist die CloseAction caFree eher mit FreeAndNil oder mit Release vergleichbar?

mkinzler 8. Mai 2008 12:20

Re: Warum macht ein TForm.Close nicht NIL
 
Daher habe ich ja geschrieben, wenn genutzt wird FreeAndNil()

hitzi 8. Mai 2008 12:21

Re: Warum macht ein TForm.Close nicht NIL
 
Oh, da hab ich doch glatt was vertauscht - sorry.

Eurowig 8. Mai 2008 12:26

Re: Warum macht ein TForm.Close nicht NIL
 
@hitzi
caFree ist dann wohl eher ein Release und kein FreeAndNil.

Wenn also das Formular nach dem Close nicht mehr benötigt wird bzw. nicht mehr vorhanden sein darf ist

Delphi-Quellcode:
MyForm.Close; <<< eventuelle OnClose Routinen ausführen
FreeAndNil(MyForm); <<< nilen und Speicher freigeben
wohl eine gute Lösung.

hitzi 8. Mai 2008 12:30

Re: Warum macht ein TForm.Close nicht NIL
 
Zitat:

Zitat von Eurowig
wohl eine gute Lösung.

Was nun? Ist FreeAndNil oder Release die bessere Lösung bei folgenden Code?
Delphi-Quellcode:
frmTest := TfrmTest.Create(Application);
try
  frmTest.ShowModal;
finally
  //was nun?
  frmTest.Release;
  //oder
  FreeAndNil(frmTest);
end;

mkinzler 8. Mai 2008 12:32

Re: Warum macht ein TForm.Close nicht NIL
 
.Release ändert den Wert der Referenzvariable nicht!

Muetze1 8. Mai 2008 12:35

Re: Warum macht ein TForm.Close nicht NIL
 
Release ist definitiv die bessere Lösung.

Und egal ob Close oder Release: man kann beides ohne Delphi-Referenz durchsuchenFreeAndNil() nutzen, wenn man z.B. im FormDestroy des jeweiligen Formulars einfach die Instanzenvariable selbst mit NIL zuweist.

hitzi 8. Mai 2008 12:49

Re: Warum macht ein TForm.Close nicht NIL
 
Ok, dann so:
Delphi-Quellcode:
frmTest := TfrmTest.Create(Application);
try
  frmTest.ShowModal;
finally
  //was nun?
  frmTest.Release;
  frmtest := nil;
  //oder
  FreeAndNil(frmTest);
end;
Ich seh immer noch nicht so richtig den Unterschied, außer dass Release nicht wartet bis dass zu entfernende Fenster fertig mit allen Botschaften ist. Was passiert, wenn ich Release verwende um beim Beenden des Programmes die Unterfenster zu schließen? Das Release fängt an das Unterfenster zu entfernen und gibt die Kontrolle noch bevor es fertig ist wieder zurück an das Hauptprogramm. Dieses schließt sich nun selber. Was aber, wenn das Release des Unterfensters länger als das Beenden des Programmes dauert?

Theoretisches Beispiel:
Delphi-Quellcode:
frmTest := TfrmTest.Create(Application);
try
  frmTest.ShowModal;
finally
  //was nun?
  frmTest.Release; //dauert 5 Sekunden - warum auch immer, aber laut Hilfe: Release gibt die Steuerung sofort an die aufrufende Routine zurück und wartet nicht, bis das Formular freigegeben wird.
  //Alles ab hier wird also ausgeführt bevor frmTest.Release überhaupt fertig ist.
  frmtest := nil;
end;
Close; //Programm selber beenden - was aber wenn frmTest.Release noch läuft?
@Muetze: meinst du das so?
Delphi-Quellcode:
procedure TfrmTest.FormDestroy(Sender: TObject);
begin
  Self := nil; //so?
end;

Muetze1 8. Mai 2008 13:35

Re: Warum macht ein TForm.Close nicht NIL
 
Zitat:

Zitat von hitzi
@Muetze: meinst du das so?
Delphi-Quellcode:
procedure TfrmTest.FormDestroy(Sender: TObject);
begin
  Self := nil; //so?
end;

Nein, nicht Self, sondern frmTest auf nil setzen...

hitzi 8. Mai 2008 13:39

Re: Warum macht ein TForm.Close nicht NIL
 
Danke für den Tipp. :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:50 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz