Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi sporadische Exception beim Freigeben von TLabels (https://www.delphipraxis.net/212155-sporadische-exception-beim-freigeben-von-tlabels.html)

Gausi 27. Dez 2022 14:27

sporadische Exception beim Freigeben von TLabels
 
Für die Anzeige einer relativ kurzen Liste von Objekt-Eigenschaften nutze ich dynamisch erzeugte TLabels. Diese verwalte ich in einer TObjectList mit OwnsObjects = True. Die Anzeige erledigt eine Methode "CreateTagLabels", die im Wesentlichen so aussieht:
Delphi-Quellcode:
TagLabelList.Clear; // Alte Labels freigeben
// neue erstellen
for i := 0 to Count-1 do begin
  newLabel := TLabel.Create(Nil); // Kein Owner, das ist ja die ObjectList
  TagLabelList.Add(newLabel);
  newLabel.Parent := Panel1;
  // newLabel.Caption := ...; Top, Left, OnClick, usw. usf.
end;
Und das knallt gelegentlich beim "Clear". Bei mir bisher gar nicht, aber ein Nutzer hat mir jetzt diesen Bugreport 2x zugeschickt. Einmal lief das Programm 2 Tage, beim nächsten Mal 8 Tage.

Der Callstack von MadExcept (gekürzt) sieht so aus.
Code:
exception message : Zugriffsverletzung bei Adresse 0066CD01 in Modul 'nemp.exe'. Lesen von Adresse 00000008.

main thread ($57e8):
Vcl.Controls           AlignNestedControls
Vcl.Controls           TWinControl.AlignControls
Vcl.Controls           TWinControl.AlignControl
Vcl.Controls           TWinControl.RemoveControl
Vcl.Controls           TControl.SetParent
Vcl.Controls           TControl.Destroy
madExcept              InterceptClassDestroy
Vcl.Controls           TControlCanvas.Destroy
System        1191  +0 TObject.Free
System.Contnrs         TObjectList.Notify
System.Classes         TList.SetCount
System.Classes         TList.Clear
NempMainUnit  5703  +2 TNemp_MainForm.CreateTagLabels
Das sieht für mich so aus, als würde das Parent-Panel versuchen, während des Freigebens der Label-Liste nochmal auf Objekte zuzugreifen, die die ObjectList schon freigegeben hat.
So wie ich den VCL-Code verstehe, sollte das aber eigentlich nicht passieren: Die Objekte in der Liste werden beim Clear der Reihe nach freigegeben, jedes einzelne benachrichtigt sein Parent darüber, welches das Control dann "vergisst". Beim nächsten Label.Free; sollte das vorherige dann im Parent verschwunden sein. Oder kann es in seltenen Fällen dazu kommen, dass sich da irgendwelche internen Messages überschneiden?

Bernhard Geyer 27. Dez 2022 15:39

AW: sporadische Exception beim Freigeben von TLabels
 
Du nutzt aber nicht Threads beim erzeugen/freigeben?

jaenicke 27. Dez 2022 15:52

AW: sporadische Exception beim Freigeben von TLabels
 
Ich würde dir raten, das Projekt mit FastMM zu kompilieren. Wenn ich es im FullDebugMode damit ausführe, bekomme ich sofort z.B. beim Beenden Fehlermeldungen, dass da Objekte doppelt freigegeben werden. Die passenden Stacktraces (vom Erzeugen, Freigeben und dem fehlerhaften Zugriff) zeigt dir FastMM auch.

Das war auch meine Idee, weshalb ich FastMM überhaupt drauf angesetzt hatte.

himitsu 27. Dez 2022 15:59

AW: sporadische Exception beim Freigeben von TLabels
 
Ja, erstmal keine Threads.

Und dann ist eine TComponentList besser, als eine TObjectList.
Oder einfach ein TComponent als Container/Liste. (weil Delphi leider Ersteres hat, aber mal wieder nicht öffentlich und man es daher selber bauen muß)
Bzw. ein Owner-Objekt nutzen und dann statt TagLabelList.Clear diesen Owner freigeben und einen Neuen erstellen.



Wo sind denn die Labels drauf?
Das wird nicht zufällig freigegeben, bevor du deine TagLabelList leer machst?

Genau dafür ist eine ComponentList, denn dort löscht das Label sich selbst raus, wenn es von jemand Anderem freigegeben würde.


Zitat:

Das sieht für mich so aus, als würde das Parent-Panel versuchen, während des Freigebens der Label-Liste nochmal auf Objekte zuzugreifen
Zitat:

Das wird nicht zufällig freigegeben, bevor du deine TagLabelList leer machst?
Nicht nochmal, sondern vorher ja immer.

Nicht nur der Owner gibt etwas frei, sondern auch der Parent.
Ist ein krankes Verhalten, was die VCL leider von der GDI übernommen hat (dort gibt es keine expliziten Owner, sonden nur einen Parent, der Alles macht),
obwohl es garnicht nötig gewesen wäre, weil die WinControls auch überleben können, selbst wenn das innere HWND und DC noch nicht mehr existiert.


TComponents haben aber ein intenes Notifications-Systen, womit man sich informieren lassen kannt, wenn es freigegeben wird. (das nutzt der Owner, Parent und z.B. eine ComponentList)

Gausi 27. Dez 2022 17:02

AW: sporadische Exception beim Freigeben von TLabels
 
Danke schonmal für die Antworten. :thumb:

Nein, Threads habe ich an der Stelle nicht. Ich klicke auf ein Element in einer VirtualTreeView, und zeige im "onClick" die Elementeigenschaften an. Ein Teil davon ist das Erzeugen dieser Labels. Ich nutze zwar durchaus mehrere Threads für einige Hintergrundarbeiten, aber die Labels sind rein VCL-Thread. das würde auch öfter knallen, denke ich. :lol:

FastMM habe ich mal probiert (du meinst doch das hier, oder? https://github.com/pleriche/FastMM4). Tatsächlich zeigt der mir am Ende an, dass etwas doppelt freigegeben wird, aber das hat hiermit nichts zu tun - da gibt es noch ein Problemchen im Finalize einer Unit. Wenn ich das (erstmal Quick&Dirty, so ganz gefällt mir die Lösung noch nicht) ins OnDestroy der MainForm verschiebe, gibt es keine solche Meldung mehr.

Die Label liegen auf einem Panel (bzw. auf einer eigenen Ableitung davon). Dieses Panel bleibt aber zur Laufzeit erhalten. Die Objekte in der Liste sollten also nicht "von außen" gelöscht werden können. Die TComponentList schaue ich mir aber auch nochmal an. Ob dadurch der Fehler behoben wird, kann ich aber ohne Reproduktionsweg nicht so richtig testen ... :stupid:

Zitat:

Zitat von himitsu (Beitrag 1516708)
TComponents haben aber ein intenes Notifications-Systen, womit man sich informieren lassen kann, wenn es freigegeben wird. (das nutzt der Owner, Parent und z.B. eine ComponentList)

Jep, das wird hier ja auch getriggert. Durch das Clear der ObjectList wird für jedes Objekt (=TLabel), das jetzt zerstört werden soll, das Parent informiert. Das Parent löscht die Referenz darauf, und ruft dann noch AlignControls auf (auch wenn das hier nicht nötig wäre, da die Labels alle alNone sind). Und dabei kommt die Exception. Meine Vermutung war also, dass das Parent doch noch Referenzen auf Objekte hat, die die Liste schon fertig zerstört hat. Aber das sollte nicht passieren, wenn ich mir den Code von TObjectList.Clear so anschaue und von all dem Gedöns, was da dranhängt ...

Uwe Raabe 27. Dez 2022 17:11

AW: sporadische Exception beim Freigeben von TLabels
 
Du könntest das Clear in ein DisableAlign/EnableAlign des Panels kapseln.

himitsu 27. Dez 2022 18:12

AW: sporadische Exception beim Freigeben von TLabels
 
Ansonsten bliebe noch dieses grauenhafte DebugDCUs wieder zu aktivieren und zu hoffen dann mehr sehen zu können.

Das Einzige, was wie ein "Offset" von 8 ausssieht, welches ich auf die Schnelle sah, wäre ResizeList.Capacity, bzw. das FCapacity.

Gausi 28. Dez 2022 13:26

AW: sporadische Exception beim Freigeben von TLabels
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1516710)
Du könntest das Clear in ein DisableAlign/EnableAlign des Panels kapseln.

Ah, so heißt das. Ich hatte BeginUpdate/EndUpdate probiert, aber das gibt es bei Panels ja nicht.

Ich habe jetzt die Liste zu einer TComponentList gemacht (weitere Änderungen neben der Deklaration und dem Create scheinen nicht nötig zu sein), und das Clear gekapselt wie Uwe es vorgeschlagen hat. Das sollte reichen. Falls nicht, muss ich später nochmal genauer schauen ...

TigerLilly 29. Dez 2022 07:11

AW: sporadische Exception beim Freigeben von TLabels
 
Möglicherweise führt das Freigeben des Labels zu einer Aktualisierung des Parents der noch nicht weiß, dass der Label freigegeben ist? Siehe auch Post von Uwe Raabe.

ConnorMcLeod 29. Dez 2022 22:50

AW: sporadische Exception beim Freigeben von TLabels
 
Mglw ist FreeNotification Dein Freund.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:09 Uhr.
Seite 1 von 2  1 2      

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