Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Verständnisfrage zu ARC (https://www.delphipraxis.net/177344-verstaendnisfrage-zu-arc.html)

Union 1. Nov 2013 12:58

Delphi-Version: XE2

Verständnisfrage zu ARC
 
Hinweis: Es handelt sich um XE5, läßt sich hier aber nicht auswählen.

Ich habe eine zur Laufzeit erzeugte Firemonkey-Komponente. Die will ich von Zeit zu Zeit neu erzeugen. Bisher war ich es ja gewohnt, das mit Free oder FreeAndNil zu machen. Leider verschwindet die Komponente aber nicht. Erst mit DisposeOf.

Das ist natürlich gefährlich, da man ja jahrelang so gearbeitet hat. Manchmal funktioniert es, manchmal nicht. Was muß man da für ein Pattern verwenden? Welche Schritte sind wann zu beachten.

Delphi-Quellcode:
interface
...
TfrmDisplay = class(TForm)
...
public
  Target : TTarget;
  Painter : TTargetPainter;
  CursorCircle : TEllipse;
end;
...
implementation
...
procedure TfrmDisplay.Init;
begin
  if Assigned(Target) then Target.Free;
  if Assigned(Painter) then Painter.Free;
  // Mit Free oder FreeAndNil bleibt die Komponente stehen und bei jedem
  // Aufruf der Init-Procedur kommt eine hinzu.
  if Assigned(CursorCircle) then CursorCircle.DisposeOf;
  ...                                            
  CursorCircle := TEllipse.Create(ImageControl1);
  ...
end;

Daniel 1. Nov 2013 13:21

AW: Verständnisfrage zu ARC
 
Gehört die FMX-Komponente irgendwem? Wenn ja, dann müsstest Du dessen .RemoveObject()-Methode aufrufen. Danach kannst Du es dann freigeben.

Union 1. Nov 2013 13:39

AW: Verständnisfrage zu ARC
 
Ja, die gehört jemand. In dem Beispiel ein Imagecontrol. Nein, das muß ich nicht. Es verhält sich plattformabhängig! Bei einer Windows-Firemonkey-Anwendung verschwindet die Komponente durch das Free. Bei iOS z.b. nicht. Ich habe bei beiden das gleiche Framework, nämlich Firemonkey. "Nur" der Compiler ist unterschiedlich. Ich will eben so was vermeiden:
Delphi-Quellcode:
{$IFDEF NEXTGEN}
{$IFDEF ANDROID}
Mist.DisposeOf
{$ELSE}
FreeAndNil(Mist)
{$ENDIF}
{$ELSE}
Mist.Free;
{$ELSE}

Daniel 1. Nov 2013 13:50

AW: Verständnisfrage zu ARC
 
Aber sicher verhält es sich plattform-abhängig. Der Compiler für Win32 / Win64 hat doch gar kein ARC.

Der NEXTGEN-Compiler ersetzt einen Aufruf von .Free durch eine Zuweisung auf NIL. Ein .Free kannst Du damit für alle Compiler gleichermaßen verwenden, das IFDEF ist nicht erforderlich.

Mit .DisposeOf() führst Du den Code aus, der im Destruktor des Objektes enthalten ist. Eine Freigabe erfolgt (allein) dadurch nicht.

Union 1. Nov 2013 13:55

AW: Verständnisfrage zu ARC
 
Mir geht es um die Plattform-Unabhängigkeit. Die ist also erst dann gegeben, wenn ich Libaries, die jahrelang immer funktionierten, mit defines komplett überarbeiten muß? Weil u.U. das Free gar nix mehr tut...

Daniel 1. Nov 2013 13:58

AW: Verständnisfrage zu ARC
 
Das .Free löst eine Referenz auf ein Objekt auf und bewirkt, dass dessen Referenz-Zähler um eines nach unten geht. Ist dieser bei Null angekommen, so wird das Objekt unmittelbar an dieser Stelle freigegeben.
Und ja, es gibt bestimmt einige Bibliotheken, die unter Win32 anständig funktionieren, aber nicht ARC-fähig sind.

Union 1. Nov 2013 14:01

AW: Verständnisfrage zu ARC
 
Durch das Zuweisen von Parent UND dem Setzen von Owner im Constructor wird also vermutlich der Referenzähler zweimal erhöht?

Daniel 1. Nov 2013 14:36

AW: Verständnisfrage zu ARC
 
Ja, allein ein Label auf einem Form hat 5 Referenzen. Parent, Owner, ein Styler, vielleicht ein Gesture-Manager - es kann viele Gründe dafür geben. Das ist nicht per se schlimm, so lange das Framework weiß, wann es was aufzuräumen hat. Deswegen ja mein Hinweis auf ".RemoveObject()". Dort werden genau diese Referenzen wieder aufgedröselt.

BUG 2. Nov 2013 01:38

AW: Verständnisfrage zu ARC
 
Zitat:

Zitat von Union (Beitrag 1234168)
Ich will eben so was vermeiden

Im Zweifelsfall kannst du es ja in einer Prozedur verstecken :mrgreen:

Habe ich es richtig verstanden, dass
Delphi-Quellcode:
Mist.removeObject();
FreeAndNil(Mist);
immer (gleich) funktionieren sollte, wenn nicht noch irgendwo andere Referenzen rumliegen, die man selbst zu verantworten zu hat :gruebel:

Das die Umstellung bzw. das Nebeneinander von manueller Speicherverwaltung und ARC nicht ohne Reibungsverluste funktioniert, ist irgendwie nicht wirklich überraschend.

Union 2. Nov 2013 08:57

AW: Verständnisfrage zu ARC
 
Da werde ich wohl mal einige Versuche mit refcount machen. Ansonsten gilt wohl als Best Practice: Sämtliche Free durch DisposeOf ersetzen.

Daniel 2. Nov 2013 09:16

AW: Verständnisfrage zu ARC
 
Nein, das mit dem Free und DisposeOf haut nicht hin.
".DisposeOf" ändert den Referenz-Zähler nicht. Es führt lediglich den Code aus, der im Destruktor enthalten ist - degradiert damit den Destruktor fast zu einer normalen Methode. Das Objekt lebt danach noch - zumindest aus technischer Sicht, selbst wenn es fachlich vielleicht nicht mehr in der Lage sein mag, einer sinnvollen Tätigkeit nachzukommen.

Zudem setzt .DisposeOf() ein Flag, das höchstwertige Bit des Referenz-Zählers. Danach hast Du auf jeden Fall ein RefCount von >= 2^32.

Man spricht davon, dass das Objekt sich dann in einer Art "Zombie-Zustand" befindet.

Ich zitiere mal aus dem DocWIKI:
Ein Weg der Betrachtung der Unterschiede zwischen Free und DisposeOf liegt in der Berücksichtigung des Zwecks. Free wird zu dem Zweck verwendet, dass eine bestimmte Referenz von einer Instanz getrennt werden soll. Dabei ist eine Freigabe des Objekts oder von Speicher nicht impliziert. Im Gegensatz dazu teilt der Programmierer mit DisposeOf der Instanz explizit mit, "sich selbst zu bereinigen". Eine Speicherfreigabe ist dabei nicht notwendigerweise impliziert, DisposeOf führt eine explizite "Vorbereinigung" der Instanz durch. Anschließend ist die Instanz von der normalen Referenzzählungssemantik abhängig, die die Instanz dann schließlich freigeben kann.

Union 2. Nov 2013 09:28

AW: Verständnisfrage zu ARC
 
Na dann bin ich ja froh dass ich jetzt weiss woher die fiesen Firemonkey-Speicherlecks kommen. Ich hab aber immer noch nicht verstanden wie ich Source wie z.b. in dem ersten Beitrag dieses Threads Mukltiplattformsicher bekomme - und das möglichst ohne Compiler-Defines wie NEXTGEN, AUTOREFCOUNT usw. abzufragen.

Konkretes Ziel war:
  • Erzeugen einer Komponente zur Laufzeit
  • Entfernen der Komponente zur Laufzeit
  • Zustand des Speichers nach dem Entfernen soll so sein wie vor dem Erzeugen

Der schöne Günther 2. Nov 2013 19:26

AW: Verständnisfrage zu ARC
 
Ich kann als reiner Windows-Kompilierer wahrscheinlich nicht wirklich mitreden. Aber ein
Delphi-Quellcode:
c:TControl
mittels
Delphi-Quellcode:
someParentControl.AddObject(c)
hinzufügen und später mittels
Delphi-Quellcode:
RemoveObject(c)
und anschließendem
Delphi-Quellcode:
c.Free()
zu entfernen ist doch eigentlich genau das richtige, oder?

Oder wird es komplizierter wenn bsp. der Owner von
Delphi-Quellcode:
c
ungleich
Delphi-Quellcode:
someParentControl
gewesen wäre?

Sir Rufo 2. Nov 2013 22:21

AW: Verständnisfrage zu ARC
 
Sobald ARC im Spiel ist, läuft IMHO ein Free ins Leere (ein Blick in die Quellen liefert da Erkenntnis).

Mein Favorit wäre hier eigentlich Delphi-Referenz durchsuchenTFmxObject.Release


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:15 Uhr.

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